Inhertitance打破封装

时间:2016-10-29 16:08:00

标签: java inheritance encapsulation

我看过许多文章,其中称继承打破了封装

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

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

任何人都可以解释一下组合是如何避免这个问题的

2 个答案:

答案 0 :(得分:1)

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

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

这会调用InstrumentedHashSet.addAll

InstrumentedHashSet.addAll adds 3 to the counter, then calls HashSet.addAll`。

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

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

每次拨打InstrumentedHashSet.add都会向计数器添加1并调用super.add

每次HashSet.add调用都会将元素添加到集合中。

最终结果是我们已经向计数器添加了6,而不是你想象的3。

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

  

任何人都可以解释一下组合是如何避免这个问题的

它可以避免它,因为当HashSet.addAll调用this.add时,对this.add的这些调用不会调用InstrumentedHashSet.add。他们直接拨打HashSet.add

事实上,如果HashSet.addAll实施Set.addAll合同,InstrumentedHashSet如何实施合同并不重要。这里没有破坏封装。

答案 1 :(得分:1)

  

我看过许多文章,其中说继承中断   封装

     

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

     

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

     

任何人都可以解释一下组合是如何避免这个问题的

“break”这个词可能过于强大,但继承肯定至少会破坏封装。

封装的一个重要目标是将API的实现与其合同分开。换句话说,希望使用API​​的客户只需要了解其“道路规则”(即其合同),而无需了解其内部工作原理。这允许大型系统的模块分离并独立发展(只要合同保持不变)。

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

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

  • 如果子类使用从基类继承的方法 - 并且该方法调用另一个方法,该方法是导出的API的一部分(所谓的“自用”API方法)。为了避免错误,子类的作者需要了解基类对方法的自我使用。这是API的客户端不需要了解的实现细节。

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

让实施细节漏出你的课程的缺点是正确使用它不再仅仅取决于API合同。每当实现发生变化时,子类都有可能会中断。