最近在维护一个老系统的时候,对复杂继承关系的难于维护深有同感,就像《代码大全(第二版)》中说的”大多数人在脑中同时应付超过2到3层继承时就有麻烦了“。应该怎么解决呢?
在GoF的《设计模式:可复用面向对象软件的基础》一书中,有这样一个原则:“优先使用对象组合,而不是类继承”。怎么理解呢?假设我们有三个基础功能“基础功能1”、“基础功能2”、“基础功能3”,三个扩展功能“扩展功能1”、‘扩展功能2“、‘扩展功能3“,扩展功能是基于基础功能扩展而来的,我们可以比较下继承和组合的差别:
看到这里,会觉得继承怎么啥都不是?显然不是,我认为这两者是配合使用的,对于复杂的功能关系,适合用组合。这个和DDD的领域模型设计是相通的,抽象实体,然后用聚合根组合实体。而对于简单且稳定的原子功能,可以用继承做扩展。也就是说整体上功能和功能之间是组合关系,单个原子功能内在简单、稳定的前提下可以用继承。这里还要考虑到系统在演进的过程中复杂度的变化,及时调整变复杂的继承关系为组合关系。
最后给自己提个醒,Rust、Go比较激进,在语言级去掉了继承,只能使用组合模式。Java比较传统,需要我们在开发中多注意,一定要写可维护的代码。
参考文献:
1、代码大全(第二版)【章节6.3】: ”大多数人在脑中同时应付超过2到3层继承时就有麻烦了“
2、设计模式:可复用面向对象软件的基础【章节1.6.5 】:“优先使用对象组合,而不是类继承”