为什么对OOP的基本概念没有一致的定义?


12

我对编程非常陌生,并且从不同来源阅读\听到不同的约定有些困惑:

面向对象的编程有4个或5个概念吗?

作为新手,我了解以下5个概念:

  • 抽象化
  • 遗产
  • 封装形式
  • 多态性
  • 模块化

那么,为什么找不到更“严格”的定义,这些概念似乎有几种排列方式呢?


7
也许是因为这不像数学(CS中的一些概念是数学,但是我认为OOP不属于这一类),因此没有严格的定义可以作为开始。例如,“模块化”有多重要?OOP真的很特别,以至于我们不得不提及它,或者如果我们正确地应用其他四个,那仅仅是它本身发生的事情吗?有些列表添加了“层次结构”,但这真的是多余的东西吗?或者只是继承和多态性而来?
thorstenmüller16年

6
忠告:作为一个非常新的程序员,您不应该对理解术语和理论如此迷恋。首先收集一些动手编程经验,这些人在说什么将变得更加明显。
菲利普

9
另一件事是,OOP随着时间而变化。在C ++早期(我知道OOP可以追溯到更远的时间),很多精力都放在继承和多态上。今天的重点更多地放在抽象和封装上。
弯曲

3
关于OO定义缺乏精确度的一些有趣的讨论可以在这里找到:c2.com/cgi/wiki?NobodyAgreesOnWhatOos
MichelHenrich

Answers:


26

之所以对面向对象编程的含义有不同的解释,是因为没有一个人或组织有权制定严格的通用定义。

面向对象的编程不是ISO标准或科学法律。这是一种哲学。与所有哲学一样,存在各种不同的解释,没有一种解释是普遍适用的。当您阅读说明设计软件体系结构时应遵循哪些概念的文章时,您应该将其视为基于作者在其专业经验中形成的观点的指南,而不是作为普遍真理。


12

面向对象编程是否包含5个或4个组件?

正如其他人提到的那样,“ OO”实际上并没有任何组件,因为它是一种思考问题解决方案建模的方式,而不是工具包或一组明确定义的流程。

作为新手,我了解以下5个组成部分:

抽象,继承,封装,多态性和模块化?

继承和多态是编程语言的功能。理解这些是很好的,但请记住它们是工具(这意味着,与其他任何工具一样,它们仅应用于解决特定问题,而不应视为目标或要努力追求的目标)。您可以(并且经常应该)编写“ OO”代码,而无需使用它们中的任何一个。我见过的一些最好的“ OO”代码很少使用继承或多态性。

抽象,封装和模块化与代码无关,而更多地与问题的处理方式,理解问题的方式以及设计和构建代码解决方案的方式有关。

同样,这些设计思想也不是“ OO”所独有的。很有可能您现在可能已经基本理解了它们,其中可能包括能够解释教科书上完美的定义,并将它们应用于一些不重要的问题。尽管将给您一个更深层次的理解测试,这是一个非常大的复杂问题,以及您可以处理多少复杂性。

理解的另一项考验是用来解决问题的方法。以及“ OO”的新手,他们经常在数据建模方面学习过OO(因为大多数人早在1990年代就已经了解过OO),并且常常最终将注意力集中在问题的错误方面-即他们专注于过多地关注数据,而他们对行为的关注不足。

例如,典型的例子通常是指实体,比如DogCatElephantSeagullShark,等新人为“OO”经常看这样的例子,马上想到:“哦,我需要称为基础机构Animal,他们甚至可以与其他结束中间实体(例如Mammal和)Amphibian,它们具有清晰的继承层次结构,每个实体中都有不同的属性。

虽然这种思维方式展示了对几种面向对象概念的非常基本的理解,但是有经验的面向对象程序员永远不会那样去做,也不会跳到那个结论(并且实际上会抱怨他们没有足够的信息),因为这种方法展示了实体建模而不是OO建模,因为人为设计的示例并未说明这些动物的行为(而且如今,许多人认为OO 的本质在于行为和功能)。

传统上,学习“ OO”的路径涉及以下时间:如果您对建模问题的行为一无所知(或了解得很少),或者当您犯了将注意力集中在实体而不是实体上的错误时,花费时间建立错误的抽象功能,尽管部分原因是因为多年来编写的许多书籍,课程和在线教程长期以来一直在引导学习者沿着这条道路前进(但趋势正在改变)。

总体而言,您的很多理解将归结为经验。到目前为止,您已经学习了这些概念,这是一个好的开始,在此过程中还需要学习更多概念(例如,“ SOLID”和“ DRY”原理),并且您将需要花费很长时间理论付诸实践,然后将所有复杂的问题“点击”到位。


2
鲨鱼和青蛙都游泳,但是一条是鱼,另一条是两栖动物。我认为该示例很好地说明了您的观点。
RubberDuck

10

“面向对象”一词是Alan Kay博士提出的,因此他是该词含义的权威来源,因此他对它进行了定义

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

让我们分解一下:

  • 消息传递(如果您不熟悉Smalltalk,则为“虚拟方法分派”)
  • 状态过程应该是
    • 当地保留
    • 受保护的
  • 万物的极端后期绑定

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

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

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

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

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

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

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

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

因此,有两种方法可以查看Alan Kay的定义:如果单独查看它,您可能会发现消息传递基本上是一个后期绑定过程调用,而后期绑定则意味着封装,因此我们可以得出结论:#1和#2实际上是多余的,并且OO都是关于后期绑定的。

但是,他后来澄清了重要的事情是消息传递,因此我们可以从另一个角度看待它:消息传递是后期绑定。现在,如果只有消息传递是可能的,那么#3就会很正确:如果只有一件事,并且该事物是后期绑定的,那么所有事物都是后期绑定的。再一次,封装来自消息传递。

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

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

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

本杰明·皮尔斯(Benjamin Pierce)在类型和编程语言中提出,面向对象的定义特征是开放递归

所以:根据Alan Kay的说法,面向对象就是消息传递。根据William Cook所说,面向对象是关于动态方法分配的(这实际上是同一件事)。根据本杰明·皮尔斯(Benjamin Pierce)的观点,面向对象是关于开放递归的,这基本上意味着自我引用是动态解析的(或者至少是一种思考的方式),或者换句话说,消息传递。

正如您所看到的,创造“ OO”一词的人对对象有一种形而上的形而上学的观点,Cook则具有相当务实的观点,而Pierce则具有非常严格的数学观点。但是重要的是:哲学家,实用主义者和理论家都同意!消息传递是OO的支柱之一。期。

注意这里没有提到继承!对于OO而言,继承不是必不可少的。通常,大多数OO语言都具有某种实现重用的方法,但不一定必须是继承。例如,它也可以是某种形式的委托。实际上,《奥兰多条约》讨论了委托作为继承的替代方法,以及不同形式的委托和继承如何在面向对象语言的设计空间内导致不同的设计要点。(请注意,实际上,即使在支持继承的语言(如Java)中,人们实际上也被告知要避免使用它,这再次表明对OO而言是不必要的。)


1
@DavidArno您的评论根本没有建设性。艾伦·凯(Alan Kay)本人声称他为这个概念创造了“对象”一词(尽管我想不是这个概念本身)。如果要与该主题的知名权威相抵触,请至少写一个更具建设性的评论。
Andres F.

1
@DavidArno另外,你的选票是你的吗?因此,有人花了很多时间就OOP的含义写出了由知名专家撰写的各种观点的综合列表,您否决了它,因为您不同意一个句子?哎呀
Andres F.

2
@AndresF。可以将这个答案概括为“尽管有两所流派,艾伦·凯的流派,还有其他所有人的流派。因为前者创造了他是对的,而每个不同意他的人都是错误的”。这是对权威谬论答案的一种呼吁。因此,下降。
David Arno

2
实际上,这个答案可以总结为“存在着三种思想流派,它们来自三个完全不同的角度,没有人不同意任何人,实际上,它们是一致的。” 语言规定论者会说,艾伦·凯(Alan Kay)发明了这个词,他说了这是什么意思,并且他说这意味着信息。语言描述主义者会说,不,艾伦·凯(Alan Kay)没说什么,我们必须看看该术语的实际使用方式,这就是库克所做的:他研究了通常被称为OO(Java,C ++)的语言。 ,C#等)的共同点,他发现
约尔格W¯¯米塔格

3
一件事:消息传递。他研究了通常被称为 OO的语言所缺乏的语言,而他发现了一件事:消息传递。象牙塔理论家采用λ演算,研究了为了获得通常被称为OO的东西而必须添加的最小特征集,他得出了开放递归,这基本上是消息传递的基础。 。
约尔格W¯¯米塔格

3

正如@Philipp所指出的那样,问题的根源在于没有正式定义使得编程语言是面向对象的。确实,这可能是一件好事。有很多方法支持OO编程,每种方法各有优缺点。关于哪种语言更“纯正OO”的讨论并没有真正实现。

但是,从您列出的5个属性来看,我认为模块化绝对是奇怪的一件事。模块化实际上是程序的属性,而不是编程语言。在语言级别,属性是“支持模块化”,通常采用“模块”或“包”机制的形式。

但是我对模块化的真正反对意见是,对于原型编程语言Smalltalk-80根本不支持模块,它不是OO编程或OO编程语言的关键。考虑一下,许多广泛使用的OOPL中对模块的语言支持是“弱”的。

模块旨在支持“大型编程”……在这种情况下,您的代码库太大,以至于一个人都无法完全理解。而且,您无需使用编程语言中的模块来模块化您的代码。


我也不会讨论其他4个属性,以及(例如)“继承”的哪些模型是否是纯OO。同样,尽管艾伦·凯(Alan Kay)因发明了OO编程而受到赞誉,但这并不一定意味着他对OO /和OOPL的定义具有首要地位。显然,事实并非如此。他是一个权威的来源,但也有谁给OO&OOPLs其他的定义是(实际上)承载较大的体重其他来源。


2
实际上,+ 1模块性已被大多数软件系统广泛接受为一种理想的属性,而与所使用的编程语言和范例无关。许多不是OO的语言都支持模块化。
Andres F.

+1 @AndresF。评论。确实,“结构化编程”和“逐步改进”(一种用于思考代码结构的技术)是从“增加复杂性导致更糟糕的软件”的坩埚中走出来的。早在COBOL之前,语言就不会受到IMHO这样的负面声誉。而且我将OO实用地视为简单的高阶结构。我的意思是,没有底层结构OO并不比最差的COBOL好。
radabobo
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.