继承打破封装? [关闭]
Posted
技术标签:
【中文标题】继承打破封装? [关闭]【英文标题】:Inheritance breaking encapsulation? [closed] 【发布时间】:2012-03-09 20:06:16 【问题描述】:人们说继承破坏了封装,我同意这一点。他们说委托更好——尽管委托中的修饰符也可以是公共的/受保护的。
那么继承破坏封装的真正原因是因为来自超类的公共/受保护修饰符的“敲击”效应被暴露给任何扩展当前子类的新类吗?
【问题讨论】:
继承破坏封装?只有在被滥用时...继承是面向对象设计的一个组成部分。 继承不会破坏封装。派生类无权访问其基类的私有成员。 “knock-on”效应是 OOP 不可或缺的一部分;如果动物会呼吸,那么预计狗、猫、人类……也会呼吸。它们没有泄露动物的内在本质;才意识到。 谷歌搜索“继承与委托”和“继承与组合”会产生一些关于该主题的非常好的文章。 很遗憾,我们不同意您问题的前提,因此对我们来说是错误的。 @Jon:请注意,您反对继承的几乎所有论点也适用于封装。假设有人可能错误地创建了一个破坏封装的受保护接口(通过继承),你为什么假设公共接口(通过委托)不能破坏封装?你的解决方案和你的前提一样有缺陷。 【参考方案1】:是的。由于它使派生类可以访问基类的成员(取决于哪种语言和哪种继承),因此可以说它破坏了封装。恕我直言,这仅适用于您坚持最严格的封装。恕我直言,可以合理地说您接受派生类作为基类的扩展,因此以某种方式相关,并没有真正破坏封装。 纯粹主义者会不同意这一点。
看看http://www.ccs.neu.edu/research/demeter/papers/context-journal/node17.html 并搜索“休息”以获得学术解释。
【讨论】:
继承不会破坏封装,即使在纯粹的意义上也是如此。如果这些成员被封装并且无法从派生类访问,那么它们就不会是公共/受保护的。 @MooingDuck 看看我回答中的链接。众所周知,继承打破了纯粹意义上的封装。 “如果允许派生类访问从基类继承的成员,则基类的更改也可能需要维护派生类。”如果允许实现更改通过接口泄漏,这是否适用于任何类的 any 消费者?我发现引用来源中的论点很弱。 派生类只有在被允许的情况下才能直接操作基类的数据(通过protected
访问修饰符)。如果您错误地将私有字段标记为受保护,那么就是您的设计被破坏了。
@Douglas “继承破坏封装”的学术论点是关于拥有“受保护”成员的能力。能够这样做的想法,即使是有意的,也是 OOP 的纯粹主义者说继承破坏封装的原因。【参考方案2】:
这取决于我们如何设计我们的类。在设计一个类时,我们应该牢记Open-Closed 原则。当我们谈论封装时,我们正在谈论修改,当我们谈论继承时,我们正在谈论扩展我们的应用程序,那么作为设计者,我们应该选择我们应该防止修改的内容(在我们的类中使用私有修饰符),从而封装我们的类以及为将来扩展保留的类的开放方面。(受保护的成员)。(想想作为 .net 语言中的部分概念,每个类都可以分成不同的文件,因此其中一些可以由程序员扩展,而另一些则使用代码生成工具生成)
【讨论】:
但是超类的设计者不能知道每个可能的类可以扩展它吗?那么继承赋予的特权会被第 6 代/第 7 代子类滥用吗? 被虐待是什么意思?当我们谈论封装时,我们谈论的是可以被私有修饰符保护的类的状态。第一个设计者应该做的就是确保该类的任何用户(按对象或按类)都不可能使用行为使对象处于无效状态 所以把超类的所有属性都设为私有,让方法受到保护,日子快乐? 并防止孩子改变关键行为。 8 年后我将投票给正确答案(打开/关闭)【参考方案3】:我认为从我的角度来看,如果在基类或超类中添加新方法,它会中断。如果A
是B
的子类,即使A
没有以任何方式修改,B
的更改也会破坏A
。 (这称为涟漪效应)
示例:假设 A
通过首先验证每个方法中的输入参数来覆盖 B
中的所有方法(出于安全原因)。如果在B
中添加了新方法并且A
没有更新,则新继承的方法会引入安全漏洞。
为了摆脱继承的陷阱,赞成或使用“组合”而不是继承,简单的聚合而不是继承,下面是一个例子:
想象两个类,Person
和 Employee
。您可以在Employee
中编写Person
并将Person
功能的请求转发给组合类,而不是要求Employee
从Person
继承,所以我们仍然可以获得重用Person
类的好处。
注意事项:
Person
类可能是抽象类或
Person
类可能与 Employee
位于同一包内的 protected
【讨论】:
【参考方案4】:想象:
class A
void foo()
...
this.bar();
...
void bar()
...
class B extends A
//override bar
void bar()
...
class C
void bazz()
B b = new B();
// which bar would be called?
B.foo();
正如您在bazz
方法中看到的,哪个bar
将被调用?第二个 B 类中的 bar
将被调用。但是,这里有什么问题?问题是 A 类中的 foo
方法对 B 类中 bar
方法的覆盖一无所知,那么您的不变量可能会被违反。因为 foo 可能期望 bar 方法的唯一行为是在自己的类中,而不是被覆盖。这个问题被称为脆弱的基类问题。
【讨论】:
以上是关于继承打破封装? [关闭]的主要内容,如果未能解决你的问题,请参考以下文章