高可维护性继承的关键在于“该不该继承”和“怎么继承不破坏契约”,应优先用接口定义行为、组合复用逻辑、谨慎使用模板方法,并严格遵守里氏替换原则。

高可维护性的类继承代码,核心不在“能不能继承”,而在“该不该继承”以及“怎么继承才不破坏契约”。设计模式不是装饰技巧,而是对继承关系是否合理、扩展是否安全的系统性判断工具。
用接口定义行为契约,而非用父类强塞实现
继承容易滑向“为复用而继承”,结果是子类被迫实现无关逻辑,或重写父类方法破坏原有语义。更稳健的做法是:把共性行为抽象为接口,让类通过实现接口表明“我能做什么”,而不是通过 extends 表明“我是什么”。
- 比如支付功能,定义
PaymentProcessor接口,含process()方法;AlipayProcessor和WechatPayProcessor各自实现,互不影响 - 避免创建一个“万能父类”如
BasePayment,里面塞进日志、重试、回调等所有可能需求——这会让子类要么空实现,要么偷偷改行为 - 若确有公共逻辑(如统一验签),可用组合:各处理器持有一个
SignatureValidator实例,而非继承它
模板方法模式:控制流程,开放步骤
当多个子类共享同一算法骨架,但某些环节差异明显时,模板方法是最自然的继承结构。父类定流程,子类只负责填空,既复用又可控。
- 父类中声明
final void execute() { prepare(); doWork(); cleanup(); },其中prepare()和cleanup()可设为protected空方法,doWork()强制子类实现 - 确保每个钩子方法(hook method)语义清晰、职责单一,不带副作用;禁止在钩子里调用父类未声明的私有逻辑
- 避免在模板方法中暴露内部状态字段给子类直接修改——用受控的 setter 或 protected 方法封装变更入口
警惕里氏替换原则(LSP)的隐性违反
LSP 不是理论教条,而是可验证的实践红线:任何使用父类引用的地方,换成子类对象后,程序输出、异常、性能边界都应保持一致。违反往往藏在细节里。
- 子类重写方法时,不扩大异常范围(如父类抛
IllegalArgumentException,子类不能新增抛IOException) - 不改变前置条件(如父类允许 null 输入,子类不能突然要求非 null)和后置条件(如父类保证返回非空集合,子类不能返回 null)
- 避免“伪继承”:比如
Rectangle和Square,看似是“正方形是矩形”,但setHeight()在正方形中会连带改 width,破坏矩形的独立宽高契约
优先组合,慎用多层/多重继承
继承绑定的是“是什么”的静态关系,组合表达的是“有什么”的动态能力。前者刚性高、耦合深;后者灵活、易测、可替换。
- 一个订单服务需要通知、风控、日志能力?不要让
OrderService继承Notifier、RiskChecker、Logger——它根本不是它们的子类;应持有这些组件的实例 - Java 不支持多重继承,但可通过接口 + 默认方法提供能力;C++ 中多重继承需明确虚基类,否则易引发菱形继承歧义
- 三层以上继承链(A → B → C → D)通常意味着职责混杂;建议拆解:B 和 C 提取共性为新接口,D 直接实现该接口 + 组合 B/C 的具体行为

















