抽象类的核心是向上提炼稳定部分、向下留出变化接口:共性体现在公共属性和固定流程方法,变化点用抽象方法强制子类实现;需符合“is-a”语义,避免过度抽象。

抽象类抽取共性,核心是“向上提炼稳定部分,向下留出变化接口”。不是简单把重复代码复制粘贴到父类,而是识别哪些逻辑所有子类都必须做、且做法一致;哪些逻辑每个子类各不相同、但又必须存在。
识别共性:从行为和数据两个维度看
共性通常体现在两类内容上:
- 公共属性:比如用户系统中,User、Admin、Merchant 都有 id、createTime、updateTime、status,这些可统一定义在抽象父类中
- 固定流程的方法:比如退款服务里,校验金额、生成单号、记录日志、更新状态——每种渠道都要走,顺序也不能变,就适合写成 final 普通方法
分离变化点:用抽象方法划清边界
子类真正不同的地方,要明确抽成抽象方法,强制实现。例如:
- 构建渠道请求参数 →
abstract Object buildRequestParam(RefundRequest req) - 发起实际调用 →
abstract RefundResult doRefund(Object param) - 解析返回结果 →
abstract boolean parseResponse(Object response)
这样模板方法 refund() 就能稳住主干流程,只让子类专注写自己那一块“不一样的代码”。
立即学习“Java免费学习笔记(深入)”;
注意继承关系的合理性
抽象类代表一种“is-a”关系,且具备业务语义上的共性基础:
- ✅ 合理:Dog 和 Cat 都是 Animal;AlipayRefundService 和 WechatRefundService 都是 RefundService
- ❌ 不合理:把 Order 和 Payment 强行塞进同一个抽象类——它们不是同一类事物,共性薄弱,容易导致职责混乱
避免常见误区
抽取共性不是越深越好,关键在“恰到好处”:
- 不要为了抽象而抽象:如果只有两个子类,且差异极小,可能直接用策略模式或简单 if-else 更清晰
- 抽象类不能被实例化,但它可以有构造方法——用于初始化共用字段(如 channelType、logger)
- 抽象方法不能是 private 或 final;普通方法若不希望被重写,要用
final显式修饰


















