为什么组合优于继承

先来看一段代码:功能是记录向Set集合中添加元素的数量

 结果会是多少?

 

没错,是9 

 

 按理来说应该是6.我们来捋一捋流程:

我们重写了add,没此添加,计数器加1,前三条执行完之后,此时计数器是3;现在来到addAll,它把传入的集合的大小累加到了计数器,此时计数器为6;然后又调用了父类的addAll(最终的插入还是调用父类),分析源码可以得知,它的内部是通过遍历集合然后挨个调用add完成的。

 现在就要注意了:它调用的是子类中重写过的add,而子类中的add是每次会计数加1的,所以又重复加了3次。

为什么父类中的addAll会调用子类重写的add而不是自身的add呢?

这就涉及到对象中的多态机制了,多态的核心是运行时方法的调用是动态绑定的,就是说方法的调用取决于运行时对象,而不是编译时的引用型对象,而代码中的运行时对象是子类而不是父类。

再次注意了,如果子类没有重写,那么调用的就是父类自身的add了。

解决方法

如果只是满足当下,方法还是有几个的,比如重写addAll,利用集合等。其实问题也挺多的。

最好的实现是使用组合--转发。

子类不直接继承父类,用一个字段把父类以组件的形式引入。通过子类的方法去调用组合对象也就是父类的方法。最大的好处是:子类对父类的方法调用是可控的,不会受到继承和多态的影响。来看一个改进版的实现:

运行结果:

现在就对了,而且是不是更好理解了。把父类组合进了子类,因为没有继承和多态这层关系,现在父类组合对象的addAll调用的当然就是自身的add方法啦。 

继承会破坏对象的封装性,子类会依赖父类的实现细节(如例子中的addAll基于add实现)保证它的基本功能。而父类随时可能会变化,子类也要跟着变化才行。 

实际中组合是否优于继承是看具体情况而言的:

如果单纯只是为了复用父类的代码,那么组合是优先考虑的,可以避免耦合和多态等行为。

 如果从语义上讲,子类和父类可以看作一个有联系的事务,那么就优先继承,因为它满足里氏替换原则:父类可以被子类无缝替换而不会影响到程序。如父类Animal子类Dog完全可以看作一个事务。

另外一个Car和Engine就应该看作包含的场景,无联系那么优先组合。

继承中子类应该扩展父类的行为,而不是修改或者重写实现父类的行为。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值