接口定义能力边界,抽象类封装接入起点;接口命名用动词或Capable/Service等后缀,方法粒度小且正交;抽象类以Abstract/Base开头,构造器强制传依赖,模板流程写死、定制点留abstract方法。

在团队开发中,抽象类和接口不是语法玩具,而是协作契约。用错地方会拖慢迭代、增加理解成本、埋下扩展隐患。核心原则就一条:接口管“能做什么”,抽象类管“怎么起步”。
接口:定义能力边界,谁都能插得上
接口是团队间最轻量的约定。它只说“你必须提供什么行为”,不说“你怎么实现”。适合跨模块、跨团队对齐能力。
-
命名统一用动词或名词+Capable/Service/Provider,比如
AsyncCapable、Retryable、PaymentService,一眼看出职责 -
方法粒度要小、正交:一个接口只表达一类能力,不混入初始化、配置、日志等无关逻辑。比如
Tracable只定义traceId()和injectSpan(),不塞进 HTTP 工具方法 -
默认方法仅用于向后兼容或极轻量逻辑,比如
default void cancel() { throw new UnsupportedOperationException(); },避免把业务流程塞进 default 方法里
抽象类:封装接入起点,降低新成员上手门槛
抽象类是团队内部的“启动模板”。它把重复代码、强制约束、基础字段提前收口,让新人不用从零写 httpClient 初始化或签名逻辑。
Java Maven 项目审查工作流的通用输入处理。当 Java Maven 项目以 ZIP压缩包或 GitLab 仓库 URL 形式提供且需要...时使用。
-
命名以
Abstract或Base开头,如AbstractApiClient、BaseOrderProcessor,明确表示“这不是最终实现” -
构造器强制传关键依赖:比如要求子类必须传
Config和HttpClient,避免运行时空指针;接口做不到这点 -
把模板流程写死,把定制点留成 abstract 方法:比如
execute()是 final 的,里面固定调用buildRequest()→doHttpCall()→parseResponse(),而前两者由子类实现
组合使用:单继承 + 多实现,能力可插拔
具体实现类不堆砌功能,而是按需组装。这样改需求时,加个接口就行,不用动骨架。
立即学习“Java免费学习笔记(深入)”;
- 写法唯一推荐:
class WechatClient extends AbstractHttpClient implements AsyncCapable, Retryable, MetricsReportable - 每个接口代表一个独立维度的能力,异步、重试、监控互不耦合,可以单独启用或替换
-
抽象类已有的工具方法(如
hmacSign())设为protected,供子类安全复用;接口里的 default 方法不能访问子类字段,不适合做这类封装
避坑要点:职责不清是最大技术债
团队最容易在初期图省事,把本该放接口的能力塞进抽象类,或者反过来把通用初始化逻辑扔到接口里——结果是后续每次加新渠道都要改抽象类,或者每个实现类都 copy-paste 一遍构造逻辑。
- 问自己一句:这个东西是所有子类“必然有”的,还是“可能有”的? 必然有(比如凭证、客户端)→ 抽象类;可能有(比如支持异步、支持重试)→ 接口
- 禁止在接口中声明非 static final 字段,Java 不允许,且违背接口“只定行为”的本质
- 抽象类里不要放业务策略逻辑,比如“满100减20”的规则应抽成策略接口,由抽象类聚合,而不是硬编码在 abstract class 里

















