继承打破了封装

Inhertitance breaks encapsulation

我看过很多文章说继承破坏了封装

http://igstan.ro/posts/2011-09-09-how-inheritance-violates-encapsulation.html

但是我无法理解它背后的概念。在给定的例子中

谁能解释一下合成是如何避免这个问题的

在您链接到的文章中的示例中:

     set.addAll(Arrays.asList("Snap", "Crackle", "Pop"));

这会调用 InstrumentedHashSet.addAll.

InstrumentedHashSet.addAlladds 3 to the counter, then callsHashSet.addAll`.

HashSet.addAll 调用 this.add 三次以添加每个元素。

但是 this.add 实际上是对 InstrumentedHashSet.add 的调用!

每次调用 InstrumentedHashSet.add 都会将计数器加 1 并调用 super.add.

每个 HashSet.add 调用都会执行将元素添加到集合中的实际工作。

最终结果是我们向计数器添加了 6,而不是您期望的 3。

为了正确实现 InstrumentedHashSet,它需要知道 HashSet.addAll 是如何实现的,而不是增加 addAll 中的计数器。但是这种知识打破了封装。子类不应该需要知道它的超类是如何实现的。


Can anyone please explain how composition is avoiding this problem

它避免了它,因为当 HashSet.addAll 调用 this.add 时,那些对 this.add 的调用不是对 InstrumentedHashSet.add 的调用。它们是直接调用 HashSet.add.

事实上,只要 HashSet.addAll 执行了 Set.addAll 合同,InstrumentedHashSet 它如何执行并不重要。这里没有破坏封装。

I have seen many articles where it says inheritance breaks encapsulation

http://igstan.ro/posts/2011-09-09-how-inheritance-violates-encapsulation.html

But I am unable to understand the concept behind it. in the given example

Can anyone please explain how composition is avoiding this problem

"break"这个词可能太强了,但是继承肯定至少会损害封装。

封装的一个重要目标是将 API 的实现与其契约分开。换句话说,希望使用 API 的客户只需要了解它的 "rules of the road"(即它的合约),而无需了解它的内部工作原理。这允许大型系统的模块解耦并独立发展(只要契约保持不变)。

不幸的是,当一个 class 从另一个继承时,子 class 通常至少依赖于基 class 的一些实现细节......这违反了封装原理。

发生这种情况的常见方式有两种:

  • 如果 subclass 使用从基础 class 继承的方法 - 并且 - 该方法调用另一个方法,该方法是导出 API 的一部分( API 方法中的 "self use")。为了避免错误,subclass的作者需要了解baseclass的自用方法。这是 API 的客户端不需要知道的实现细节。

  • 受保护的成员。有时子 class 无法在不访问父 class 的数据或行为的情况下实现功能。 Java 提供 protected 访问类型以允许 subclasses 访问成员。通过这种方式,subclass 可以非常直接地访问信息和方法,否则这些信息和方法将被封装在父 class 中。因此,subclass 依赖于父级的实现细节。

从您的 class 中泄露实施细节的不利之处在于,它的正确使用不再仅取决于 API 合同。每当实现发生变化时,subclasses 都有可能中断。