平行继承的具体实例、产生原因及相关定义逻辑咨询
平行继承层次问题解答
尝试通过继承实现代码复用可能会产生平行继承层次结构(parallel inheritance hierarchies)
典型实际场景
举电商系统开发的常见案例:
- 第一个继承层次是商品领域类:基类为
Product,按商品类型扩展出子类PhysicalProduct(实物商品)、DigitalProduct(虚拟商品)、SubscriptionProduct(订阅商品) - 第二个继承层次是商品详情渲染类:基类为
ProductRenderer,对应不同商品类型的渲染逻辑,扩展出PhysicalProductRenderer、DigitalProductRenderer、SubscriptionProductRenderer
此时只要你给Product新增一个子类,比如PreSaleProduct(预售商品),就必须同步给ProductRenderer新增对应的PreSaleProductRenderer才能完成渲染逻辑。如果后续还叠加了订单结算、物流适配等其他继承层次,每次新增商品类型就需要在多个继承链上批量新增子类,维护成本会快速膨胀。
根本原因与来源
平行继承的本质是将业务中多个独立变化的维度,通过继承的方式做了强绑定。
上述案例中,「商品的业务属性规则」和「商品的前端渲染逻辑」本身是两个完全可以独立变化的维度:比如后续要新增PC端、小程序端的渲染差异,按继承的思路还要给每个商品类型分别新增对应端的渲染子类,代码量会直接呈指数级增长。
至于触发批量新增子类的需求,通常是两个因素共同作用的结果:
- 业务上下文本身确实存在多个独立变化的维度,比如不同商品类型的属性、渲染逻辑差异是业务天然存在的
- 技术选型时选择了继承来实现每个维度的差异化,且不同继承链的类之间存在固定的一一绑定关系,才会导致扩展一个继承链时必须同步扩展其他关联的继承链。如果一开始就用组合而非继承的思路,将渲染逻辑作为独立组件注入到商品类中,就不会出现这类问题。
C2 Wiki 数学定义解释
C2 页面的定义本质是用集合映射逻辑描述平行继承的特征,拆解为大白话如下:
- 首先定义两个类的集合A、B,分别对应两个存在关联的继承层次,比如上述案例中A是所有商品类的集合,B是所有渲染器类的集合
- 两个集合之间存在稳定的双射关系:A中的每个类都唯一对应B中的一个类,反之B中的每个类也唯一对应A中的一个类,且这个对应关系由业务语义绑定,不是偶然出现的
- 每当你给A新增一个子类(集合新增元素),就必须给B也新增一个对应的子类来维持这个双射关系,满足这个特征的就是平行继承层次。
推导逻辑非常直白:两个继承链的一一绑定关系,本质是强行把两个独立的变化维度合并成了一个维度,每新增一个业务变化点就需要在两个继承链上各加一个类,本质是继承复用带来的冗余设计坏味道。
内容的提问来源于stack exchange,提问作者Epsilon Away
相关产品推荐
相关产品推荐

