为什么继承,封装和多态性不是OOP的支柱?[关闭]


16

有一天,我去了一个Stack Overflow聊天室,看到一句话,它表明继承,封装和多态性是OOP的支柱(从某种意义上说,它们是基础,是唯一的构造)。

另外,还有一个类似的问题,在大学考试和工作面试中经常有人问我,正确的答案始终是问题标题中的声明(“是的,继承,封装和多态性是OOP的基础。 )。

但是在Stack Overflow聊天中,我被严重嘲笑,参与者强烈不同意这种说法。那么,这句话有什么问题呢?

在后苏联和美国的大学里,程序员似乎接受过不同的培训吗?

美国/英国程序员是否不将继承,封装和多态性视为OOP的支柱?


7
您的问题没有上下文;我们不知道SO聊天中的人们在想什么,或者他们在回应什么。也许您可以链接到聊天室中的对话,所以我们可以看看吗?就是说,我认为这最好在聊天室解决,而不是在这里解决。
罗伯特·哈维

1
@Robert,过去太多时间了。我什至根本找不到对话的链接。但我同意背景很重要。我不是想怪别人,也不是说自己是聊天侵害的无辜受害者,我只是想知道真相。
PaulD

5
休息室。您是否先穿上了防火服?
罗伯特·哈维

1
我对这句话的唯一含义是“您可以不带任何OOP就拥有OOP”(是的,但至少对于封装没有意义)或“您也可以在OOP之外使用它们”之类的意思。
SJuan76

2
Imo OO只有一个支柱,那就是“国家”。一旦您的大脑思考了状态,您就会获得OO。
Pieter B

Answers:


40

美国/英国程序员是否不将继承,封装和多态性视为OOP的支柱?

许多程序员认为它们是支柱,许多大学都以这种方式教授面向对象。

不幸的是,这也是一种短视的观点。

  • 继承只是用于实现OOP的一种机制,可以被滥用而不进行OOP。
  • 封装是一个概念,可用于各种编程(不是OOP)。
  • 多态是... trait(?),用于描述计算的行为方式。有很多方法可以实现多态,但并非所有方法都是面向对象的。

OOP几乎没有基础,因为实际上它是非常概念性的:“通过将事物视为对象-紧密结合的数据和功能束来接近程序的设计。”

而且,尽管现代程序设计对以“纯粹的面向对象的方式”做事的看法不佳,但是大多数熟练的程序员都会同意SOLID原理(或某些子集)是“面向对象编程的支柱”的更好的候选者(即使他们适用于非OOP)。这些根本不符合这些条款。相反,他们使用软件实体(对象是一个),接口(C#/ Java / etc interface是一个),抽象和子类型(继承是一种形式)的概念。


10
对基本无法回答的问题的体面回答。
罗伯特·哈维

3
是否存在OOP?
图兰斯·科尔多瓦

5
我认为只有封装是OOP的“支柱”。OOP与结构化编程之间的最大区别是对象包含代码数据,而不仅仅是数据(例如,经典的C结构)。另外两个概念主要用在OO语言中,但既不限于OO,也不是OO所必需的。

3
@Snowman封装也不限于OOP。人们一直在用C和功能语言实现抽象数据类型。
Doval

2
@JörgWMittag在消息传递方面有很好的答案。消息传递的思想必然需要封装。消息通常传递给对象上的函数方法,然后该对象作用于封装在其中的状态。这并不是说非OO语言也不能具有消息传递或封装,而只是它们是OOP的基础思想。

23

tl; dr:不带OO就可以继承,不带OO可以具有封装,不带OO可以具有多态性,甚至不带OO也可以同时具有这三个。另一方面,您可以拥有没有继承的OO。另外,有不同类型的封装(面向ADT和OO),IOW并非所有封装都是OO。

长版:

术语“面向对象编程”是Alan Kay发明的,因此他可以决定它的含义。而且他是这样定义的:

对我而言,OOP意味着仅消息传递,本地保留和保护以及状态过程的隐藏以及所有事物的极端后期绑定。

实现明智的,消息是后期绑定过程调用,如果过程调用后期绑定,那么你就不能在设计时知道什么你要电话,所以你不能对状态的具体表现做任何假设。因此,实际上是关于消息传递的,后期绑定是消息传递的一种实现,封装是它的结果。

后来他澄清了“ 大想法是'消息传递' ”,并遗憾地称其为“面向对象”而不是“面向消息”,因为术语“面向对象”将重点放在不重要的事物上(对象)并分散真正重要的内容(消息传递):

轻轻提醒一下,我在上一期OOPSLA上做了一些尝试,试图提醒大家,Smalltalk不仅是其语法或类库,甚至与类无关。很抱歉,我很久以前为该主题创造了“对象”一词,因为它使许多人专注于较小的想法。

最大的想法是“消息传递”-这就是Smalltalk / Squeak的核心所在(这在我们的Xerox PARC阶段中从未完全完成)。日语有一个小字-ma-代表“介于两者之间的事物”,也许最接近的英语是“ interstitial”。制作出色且可扩展的系统的关键在于设计模块的通信方式,而不是设计其内部属性和行为。想想互联网-要生存,它(a)必须允许超出任何单一标准的许多不同种类的想法和实现,并且(b)允许这些想法之间具有不同程度的安全互操作性。

(当然,今天,大多数人甚至不专注于对象,而是专注于类,这是错误的。)

消息是根本,以面向对象,无论是作为隐喻和作为一种机制。

如果您向某人发送消息,您将不知道他们如何处理该消息。在只有你可以观察到的东西,是他们的反应。您不知道他们是否自己处理消息(即对象是否具有方法),是否将消息转发给其他人(委托/代理),甚至他们是否理解。这就是封装的全部内容,这就是OO的全部内容。您甚至无法区分代理与真实对象,只要它能响应您的期望即可。

“消息传递”的一个更“现代”的术语是“动态方法分派”或“虚拟方法调用”,但它失去了隐喻,而专注于该机制。

威廉·R·库克William R. Cook)重新审视的《关于理解数据抽象》以及他关于“简化的,现代的“对象”和“面向对象”定义的建议”中也提出了类似的观点。

动态分配操作是对象的基本特征。这意味着要调用的操作是对象本身的动态属性。无法静态识别操作,并且通常无法准确地响应给定请求执行什么操作,除非运行该操作。这与始终动态分配的一流函数完全相同。

在Smalltalk-72中,甚至没有任何物体!有是得到了分析,重写和重新路由信息流。首先出现的是方法(解析和重新路由消息流的标准方法),后来出现的是对象(共享某些私有状态的方法组)。继承来得晚了很多,而引入类只是作为支持继承的一种方式。如果Kay的研究小组已经了解原型,那么他们可能根本不会引入类。

每个程序员都应该阅读《重新理解数据抽象》。它详细解释了对象和抽象数据类型之间到底有什么区别。他给出了使用Java的例子,那就是对这个问题非常重要,因为在这两个的ADT的例子他使用继承,封装和多态对象的实例,但只有一个的例子是面向对象!换句话说:您可以具有继承,封装和多态性,甚至可以同时拥有这三个,而仍然没有OO。

另一方面,您可以拥有没有继承的OO。就像我在上面暗示的那样:Smalltalk的原始版本(由“面向对象程序设计”一词的发明者Alan Kay设计的语言)没有继承。

最后但并非最不重要的一点是,《奥兰多条约》讨论了委托作为继承的一种替代方法,以及不同形式的委托和继承如何在面向对象语言的设计空间内导致不同的设计要点。(请注意,实际上,即使在支持继承的语言(如Java)中,人们实际上也被告知要避免使用继承,这再次表明对OO而言是不必要的。)


您可以具有“继承性”,“多态性”和“继承性” ...方法上可能有错别字:)
slebetman

1
这个答案让我希望我们也可以“最喜欢”的答案。
Chan-Ho Suh 2015年

艾伦·凯(Alan Kay)的定义已经过时。OO需要继承,并且如果您可以像在C ++中那样同时执行运行时和编译时绑定,则您也可以获得与C相当的性能。
ErikAlapää17年

不,他的定义是正确的。您完全不需要继承就可以成为OO。原型语言不像C ++那样使用继承,它们仍然是面向对象的。继承仅用于实现代码重用,它甚至不是最好的方法,例如,有很多更好的语言带有mixin。它也与绑定无关,因为您可以进行动态分派,甚至在使用虚拟方法的C ++中也是如此。性能与这些无关,它们是高级概念,与性能无关。实际上,您可以在C中实现消息传递并成为OO
Luiz Felipe
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.