抽象类管身份、接口管能力:抽象类适合共享状态和通用逻辑的继承体系,接口用于解耦无关类的共同行为;选型依据数据结构共性、能力普适性及多角色需求。

设计规范的核心不是死记语法,而是理解“抽象类管身份,接口管能力”这个基本定位。用错地方,代码会越来越难扩展;用对了,加新功能就像插模块一样简单。
抽象类聚焦“是什么”和“怎么复用”
它适合描述有明确继承关系、共享状态和部分通用逻辑的一组类。
- 当多个子类共用字段(比如name、id、createTime)时,放抽象类里比每个子类重复写更合理
- 当有一段逻辑90%的子类都一样(比如日志记录、参数校验、结果封装),就写成具体方法,让子类直接继承使用
- 抽象方法只留真正必须由子类差异化实现的部分,比如calculatePrice()、serialize()
- 避免在抽象类里塞大量final或static方法,它们会限制子类灵活性
接口聚焦“能做什么”和“怎么解耦”
它本质是一份行为契约,不关心你是谁,只关心你能提供什么服务。
- 一个接口只表达一个清晰的能力维度,比如Payable、Exportable、Retryable,别搞大而全的CommonService
- 优先用接口类型声明变量和参数,比如List<Payable> orders,而不是List<Order>,这样未来加个Refund类也能无缝接入
- Java 8+ 的default方法适合加通用但非强制的辅助逻辑(比如toXml()),但别让它变成业务主流程
- 接口里定义的常量要真有必要才放,别当成配置中心用
选型时看这三个关键问题
遇到建模犹豫时,直接问自己:
立即学习“Java免费学习笔记(深入)”;
- 这个东西有没有共同的数据结构?有 → 抽象类更合适
- 这个东西是不是多种完全无关的类都能具备的能力?是 → 接口更合适(比如Runnable,线程、定时任务、消息处理器都可以实现)
- 以后会不会出现一个类既要像A又要像B?比如“既是支付渠道,又能导出报表” → 必须用接口,因为Java只允许单继承
实战中容易踩的坑
很多重构难题其实源于最初的设计偏差:
- 把本该是接口的“能力”硬塞进抽象类,导致后续想给其他类赋予同样能力时,只能复制粘贴或强行拉一条继承线
- 抽象类里堆太多具体方法,结果某个子类根本不需要其中70%,却不得不继承并忽略
- 接口方法签名频繁变动,说明当初没想清楚契约边界;稳定接口应尽量小而稳定,变更是常态的逻辑放到实现类里
- 一个类既继承抽象类又实现一堆接口,但接口方法全是空实现——这说明接口设计脱离了真实需求


















