我遇到了以下几点the advantage of object composition over class inheritance.但我经常在很多文章中看到以下句子
在对象组合中,通过收集对其他对象的引用的对象在运行时动态获取功能.这种方法的优点是可以在运行时替换实现.这是可能的,因为对象只能通过它们的接口访问,所以只要它们具有相同的类型,就可以用另一个对象替换它们.
但怀疑可能是天真的,因为我是初学者.如何在运行时替换实现?如果我们编写一行新代码,是否需要编译以反映更改?那是什么意思replacing at runtime?很混乱.或任何其他魔法,幕后活动发生.任何人都可以回复.
考虑一个Stack. 一个简单的实现Stack利用了List幕后。所以天真地,你可以扩展ArrayList. 但现在如果你想要一个Stack由 a 支持的单独的LinkedList类,你就必须有两个类:ArrayListStack和LinkedListStack。(这种方法的缺点还在于List在 a 上公开方法Stack,这违反了封装性)。
如果您使用组合,则可以由调用者提供List支持,并且您可以拥有一个可以采用 a或 an的类,具体取决于用户所需的运行时特征。StackStackLinkedListArrayList
简而言之,实现“在运行时更改”的能力不是指类的实例能够在运行时更改其实现,而是指该类在编译时不知道其精确实现是什么。
另请注意,使用组合的类不需要允许在运行时(由调用者)选择委托实现。有时这样做会违反封装性,因为它会给调用者提供更多关于类内部的信息,而不是期望的。在这些情况下,组合仍然具有仅公开抽象方法并允许在以后的修订中更改具体实现的好处。
顺便说一句,我使用 Stack 的例子,因为它不是纯粹的假设。 Java 的 Stack 类实际上是扩展的Vector,这使得它永远承载着同步的包袱和数组支持的列表的性能特征。因此,强烈建议不要使用该类。
正确使用集合组合的完美示例也可以在 Java 库中找到,位于Collections.newSetFromMap(Map). 由于 anyMap可用于表示 a Set(通过使用虚拟值),因此此方法返回由传入的Set 组成Map的 a 。然后,返回的内容Set继承了它所包装的特性Map,例如:可变性、线程安全性和运行时性能——所有这些都无需创建、、等的并行Set实现。ConcurrentHashMapImmutableMapTreeMap