本文主要想了解:
- 为什么组合优于继承,多用组合少用继承。
- 如何使用组合来替代继承
- 哪些情况适用继承、组合。
- 有哪些设计模式使用到了继承、组合。
继承是面向对象的四大特性之一,用来表示类之间的 is-a 关系,可以解决代码复用的问题。
但当继承层次过深、过复杂,也会影响到代码的可维护性。在这种情况下,我们应该尽量少用,甚至不用继承。
?
可以利用组合(composition)、接口、委托(delegation)三个技术手段,一块儿来解决刚刚继承存在的问题:继承层次过深、继承关系过于复杂会影响到代码的可读性和可维护性。
如下例子:
- 接口实现功能的拓展:接口表示具有某种行为特性。接口可以拓展类的行为。
- 通过组合和委托技术来消除代码重复。
?
替代复杂的继承关系逻辑
我们知道继承主要有三个作用:表示 is-a 关系,支持多态特性,代码复用。而这三个作用都可以通过其他技术手段来达成。
- 比如 is-a 关系,我们可以通过组合和接口的 has-a 关系来替代;
- 多态特性我们可以利用接口来实现;
- 代码复用我们可以通过组合和委托来实现。
所以,从理论上讲,通过组合、接口、委托三个技术手段,我们完全可以替换掉继承,在项目中不用或者少用继承关系,特别是一些复杂的继承关系。
?
总体原则
如果类之间的继承结构稳定(不会轻易改变),继承层次比较浅(比如,最多有两层继承关系),继承关系不复杂,我们就可以大胆地使用继承。
反之,系统越不稳定,继承层次很深,继承关系复杂,我们就尽量使用组合来替代继承。
?
相关设计模式
有一些设计模式会固定使用继承或者组合。
?
我们必须使用继承的场景
如果你不能改变一个函数的入参类型,而入参又非接口,为了支持多态,只能采用继承来实现。
如下:
其中 FeignClient 是一个外部类,我们没有权限去修改这部分代码,但是我们 希望执行encode时按照司内逻辑来进行encode。 这个时候,我们只能采用继承来实现了。
?
参考:《设计模式之美》王争