抽象类管骨架复用,接口管能力契约:接口定义稳定对外契约、划清模块边界、支持多实现;抽象类封装同源类的通用状态、流程与默认行为;二者分层协作构建清晰架构。

用抽象类和接口规范项目架构,核心是把“谁是什么”和“谁能做什么”分开管理:抽象类管骨架复用,接口管能力契约。不是语法上能写出来就行,而是要让代码结构反映业务本质。
用接口定义稳定对外契约
接口适合划清模块边界、暴露能力、支持多实现。一旦发布,就尽量别改签名——它代表的是系统对外承诺的行为。
- 所有服务入口、回调通知、数据转换逻辑,优先定义成接口,比如 OrderService、NotificationHandler、Serializer<T>
- 跨领域能力(如日志、审计、序列化)统一抽为接口,不同模块可自由实现,互不耦合
- 需要组合多种能力的实体(如一个订单既要可审计、又要可导出、还要可校验),必须用接口,因为 Java 不支持多继承
用抽象类封装共性骨架逻辑
抽象类适合收拢同源类的通用状态、初始化流程、模板方法和默认行为,它承载的是“这一族东西的共同根基”。
- 当多个实现类天然属于同一类事物(如各种 Exporter:PDFExporter、ExcelExporter),且共享字段(fileName、timeout)、资源(outputStream)、流程(prepare → execute → cleanup),就该用抽象类
- 想强制子类走固定流程但允许定制关键步骤?模板方法模式直接落地,比如 AbstractReportGenerator 定义 generate() 模板,留出 fetchData() 和 formatResult() 由子类实现
- 需要控制子类构造方式(比如必须传入 Config 或 Executor),抽象类有构造器,接口没有
二者配合构建三层结构
真实项目里,接口和抽象类不是二选一,而是分层协作:接口定边界,抽象类填骨架,具体类做优化。
立即学习“Java免费学习笔记(深入)”;
- 先定义顶层接口(如 CacheClient),只声明 get()、put()、evict() 等契约,供上层调用和测试桩使用
- 再提供抽象实现类(如 AbstractRedisCacheClient),封装连接池管理、序列化、重试逻辑、监控埋点等通用功能
- 最后由具体类(如 ClusterRedisCacheClient、StandaloneRedisCacheClient)专注适配差异点:集群路由、节点发现、故障转移策略
避免常见设计偏差
有些做法看似合理,实则破坏架构清晰性。
- 不要为了“看起来更抽象”而把所有父类都做成抽象类——如果只是空壳、无字段、无默认逻辑、无构造约束,那它大概率该是接口
- 不要在接口里塞大量 default 方法来替代抽象类——default 方法适合补丁式扩展,不是主干逻辑载体;它不能带字段、不能设 protected 成员,复用能力有限
- 已有类层次较深时,别硬插一层抽象类去“统一”,先确认是否真有共性结构;否则容易变成只为继承而继承的累赘


















