组合优于继承——为什么这么说?
在面向对象设计中,我们经常会遇到“继承”和“组合”这两种复用代码的方式。许多人听过一句经典的话:“组合优于继承”。这句话到底是什么意思?为什么组合会被认为比继承更好用呢?
继承和组合的本质区别
可以把继承想象成“焊接”——父类和子类之间是强绑定的关系,像金属焊接在一起一样紧密。子类继承了父类的属性和行为,父类的改变往往会直接影响子类,牵一发而动全身。
而组合则更像“拼接”——将不同的组件或对象灵活组装在一起,像拼图一样可以自由组合,关系松散,变更一方不会强制影响另一方。
为什么说组合优于继承?
- 继承是强绑定,修改父类会影响子类
继承绑定了父类和子类的实现细节,父类的任何修改都有可能引发子类行为的变化,甚至导致意外的Bug。这种“脆弱基类问题”使得父类变更变得非常谨慎和困难。 - 继承层次可能过深,增加理解和维护成本
实际项目中,继承层次常常超过三层、五层,甚至更多。调试或阅读一个类时,需要逐层向上追溯父类,增加理解难度和维护成本。而且深层继承会导致设计变得僵硬,难以扩展。 - 组合更加灵活,易于扩展和维护
组合通过将不同对象或模块组装起来,彼此之间松耦合。你可以在运行时替换或扩展组件,不必改动已有代码,符合开闭原则(对扩展开放,对修改封闭)。同时避免了继承层次带来的复杂性。
总结
继承虽然简单直接,适用于“is-a”关系的建模,但强耦合和层次深的问题限制了它的灵活性。组合则更符合现代软件设计追求的松耦合、高内聚原则,提升代码的可维护性和扩展性。
因此,在设计系统时,应优先考虑组合,而不是轻易使用继承。只有在确实需要表达“父类-子类”明确层次关系时,继承才是合适的选择。
抽象类与接口
“抽象类是事物的抽象,接口是方法的抽象”。