设计原则 — 多用组合少用继承
1. 含义
原则的含义挺简单,就是推荐多用组合代替继承。
2. 优点
可以解决由于继承层次过深导致的一部分可读性及可维护性问题。
要具体阐述上述优点,需要先说明关于继承层次过深带来的困扰,
主要体现在两个方面:
父类中的方法,子类不一定都需要
当不需要时会用空实现来重写,如此确定是否有某个功能,需从方法声明+实现才能确定。
父类中的方法,有些子类要复用不重写,有些子类要重写
那找运行中方法的真实实现会费劲。
当继承层次深+上述两类方法越来越多,可读性必然下降;
那当需要修改继承层次更低的代码时,评估改动的影响范围也就变难了,可维护性也就下降了。
而使用组合、接口、委托恰好可解决继承层次深所带来的困扰。
考虑第一种情况 父类中的方法,子类不一定需要;
可通过将方法抽象至接口,需要此功能的子类实现该接口,无需此功能的子类则不实现;
逻辑需要复用的话,可新建实现类来实现该接口,再将新建类通过组合的方式整合到相应子类,并在相应方法将调用逻辑委托给组合类处理。
这样做之后会发现:无此功能的子类无需依赖它不关心的东西了,可读性、可维护性会有所提升。
考虑第二种情况 父类中的方法,有些子类要复用不重写,有些子类要重写
这种情况其实是方法的实现存在多种,那可使用上述方法,不同的是新建多个实现类,子类需要哪个实现就将相应的实现组装进来。
这样做之后会发现:找到方法相应的实现是不是就变简单了,不需要从一堆继承类中找到底是何实现,那可读性、可维护性会有所提升。
上述提到的两种情况:需要在类多了、继承层次深了才能深刻的感受到组合带来的对可读性、可维护性所带来的改善。
而对于一个类如此拆分读者可能并未感受到便利,甚至还感觉变复杂了?
3. 缺点
回答上述问题:一个类如此拆分后变复杂的感受是没错的!
因为组合代替继承需要做更细力度的拆分。也就意味着需要定义更多的类和接口,必然会增加代码的复杂程度和维护成本。
那当类比较少、继承层次不深,前述提到的
1.依赖不关心的方法所带来的不易读影响,只是非常小范围的、甚至于无;
2.找方法实现难的影响实际是不存在的,就只那么几个类;
反而非得做拆分,增加了一堆类,会降低可读性和可维护性。
4. 如何做
那前面提到了优缺点,所以这条原则的使用存在适用场景:
如果类之间的继承结构稳定(不会轻易改变),继承层次比较浅(比如,最多有两层继承关系),继承关系不复杂,我们就可以大胆地使用继承。
反之,系统越不稳定,继承层次很深,继承关系复杂,我们就尽量使用组合来替代继承;如果明显能看到前述提到的继承出现的两种情况带来的困扰,就应使用组合来代替继承。
所以我认为这条原则更多的是提醒我们当使用继承的时候,多考虑一下,是否用组合更合适。
版权声明: 本文为 InfoQ 作者【Lemoon Can】的原创文章。
原文链接:【http://xie.infoq.cn/article/886ec53149748bbeb7b6e06f5】。
本文遵守【CC-BY 4.0】协议,转载请保留原文出处及本版权声明。
评论