面向对象范式无疑是编程中最相关的主题之一,可以在 SOLID、GoF 设计模式或对象 Calhistenics 等多个行业最佳实践中找到,甚至可以在 Java 等极其流行的语言中找到、C#、Ruby、PHP、JavaScript 等。鉴于这种相关性,它也成为在线讨论甚至学术界本身争论的主题。
围绕该范式的主要争议之一是:面向对象实际上是什么?由于没有人就其含义达成一致,这就是各种类型的互联网争论中问题的症结所在,例如当有人声称他们的语言是真正面向对象的而其他语言不是,或者某些语言并不是真正面向对象时 -定向等
乍一看这似乎很愚蠢,但这背后隐藏着一个问题,那就是对于什么是面向对象确实没有正式的定义。因此,当批评与范式相关的事物时,我们无法确定它是否公平,因为没有人知道真相到底是什么,这只会导致一场双方都可以指责对方的争论。攻击稻草人,因为他们不同意他们所辩论的内容的定义,这导致他们在谈论同一件事的同时谈论不同的事情。
发生这种情况是因为它不是产生于可以被确定为讨论主要来源的正式基础,例如结构化/程序范式 - 它源于 Boehm-Jacopini 定理和文章 Go-to 声明被认为是有害的 -或者是从lambda演算诞生的泛函,相反,从技术上来说,它有两个不同的起源,这让事情变得非常困难,毕竟,甚至很难说哪个是第一个面向对象语言,无论是Simula 或 Smalltalk。
如果你之前没有接触过这个话题,你可能会觉得我在这里描述的一切有点奇怪,毕竟我们都学习面向对象,我们每天都用文字交流,一切似乎都在正常进行,通讯中没有噪音吧?
您甚至可能认为这很容易,因为即使我们查看不同的来源,例如互联网上的通用教程、维基百科,或者即使我们接受正规教育(例如技术课程或大学),我们会发现与我所说的非常相似的定义:面向对象的四大支柱:
但这实际上只讲述了故事的一部分,因为正如我之前指出的,实际上存在两种不同的面向对象思维流派,一种源于 Simula 中创建的传统,并由 C++ 开发和普及,另一个是在 Smalltalk 创造的传统中发展起来的。
即使我们可以接受C++传统中历史胜利的一面(因为目前绝大多数被认为是OO的语言比Smalltalk更遵循其思想),即Simula在4个支柱,究竟是这4个还是真的应该是4个,目前还没有达成共识。例如:
这样,正如 Bjarne Stroustrup(C++ 之父)在他的面向对象定义中所说:
“面向对象”的任何定义在历史上都应该是可以接受的。言语仅用于沟通,只有当我们就其含义达成一致时,它们才有意义。
~ Bjarne Stroustrup,改编自英文免费翻译
这就是为什么我想采用整体方法(分析整体而不是部分的声音)来分析我的定义应该考虑什么。在此我将根据 4 个标准按重要性顺序进行评估:
让我们首先定义我们的历史起点,首先我们将决定选择哪一边作为主要来源,然后遵循其作者的面向对象含义作为我们定义的基础,除了使用它作为比较参数来判断哪一组原则包含在其中是有意义的。
在这个问题上,我喜欢 Alan Kay 发明了“面向对象”而不是“对象”的观点,所以我们的基础将是他对面向对象的看法,我们可以用几句话来总结:
只是一个温和的提醒,我在上一次 OOPSLA 中努力提醒大家,Smalltalk 不仅仅是它的语法或类库,也不是关于类的。我很遗憾很久以前为这个主题创造了“对象”这个术语,因为它导致很多人关注更小的想法。
最重要的想法是“消息传递” - 这就是 Smalltalk/Squeak 的核心所在......
~ Alan Kay,改编自英文意译
我想到了像生物细胞和/或网络上的个体计算机这样的对象,它们只能通过消息进行通信(因此消息很早就出现了 - 我们花了一段时间才明白如何足够有效地用编程语言发送消息有用)。
我想删除数据。 B5000 几乎通过其令人难以置信的硬件架构做到了这一点。我意识到整个细胞/计算机的隐喻会消除数据,而“
我的数学背景让我意识到每个对象都可能有多个与之相关的代数,并且可能存在这些代数族,并且这些代数将非常有用。 “多态性”这个术语是后来才强加的(我认为是 Peter Wegner 提出的),而且不是很有效,因为它实际上来自函数的命名法,而我想要的不仅仅是函数。我发明了一个术语“通用性”来以近乎代数的方式处理通用行为。
我不喜欢 Simula I 或 Simula 67 继承的方式(尽管我认为 Nygaard 和 Dahl 只是伟大的思想家和设计师)。因此,我决定放弃继承作为内置功能,直到我更好地理解它。
~ Alan Kay,改编自英文意译
POO 对我来说只是意味着消息交换、本地数据保留以及状态保护和隐藏,以及所有事物的极端后期绑定。
~ Alan Kay,改编自英文意译
由此我们可以得出结论,使用 Kay 的定义来看待面向对象程序的视角如下:
程序被视为通过消息交换进行通信的对象网络,其目的是通过避免数据、专注于交互来进行编程,以便一条消息可以承载多种含义。
说到视角,这是 Simula 的创建者在他们的《BETA 编程语言中的面向对象编程》一书中使用的部分来描述框架的概念框架,即描述我们如何看待框架的结构以某种范式编写的程序,例如在过程编程的情况下,他们将其描述为:
程序的执行被视为操作变量的(部分有序)过程调用序列。
~ 尼加德 (Nygaard),改编自英文意译
功能性情况下:
程序被认为是一个数学函数,它描述了输入和输出之间的关系。
~ 尼加德 (Nygaard),改编自英文意译
面向对象:
程序的执行被视为物理模型,模拟世界真实或想象部分的行为。
~ 尼加德 (Nygaard),改编自英文意译
因此,即使我们的重点是 Alan Kay 的定义,考虑到 Krysten Nygaard 和 Ole-Johan Dahl(Simula 的创建者)在面向对象语言中的功能方面做出的巨大贡献,以及他的观点已经过时了时间,考虑到几乎每个现代教程仍然遵循这个故事,即对象代表现实世界的概念,甚至被形式化为抽象定义的一部分,我认为将他的观点纳入我们的最终定义是合适的
。因此,如果可以提出将两种传统调和为统一定义的论据,从而尊重我们的整体分析方法,我会尝试。
因此,由于它不一定是我们当前的定义所独有的,我们可以通过以下方式增加它:
程序被视为对象网络,这些对象是领域概念的表示,通过消息交换进行通信,其目的是编程避免数据,专注于交互,以便消息可以承载多种含义。它的总体结构类似于对世界真实或想象部分的行为的模拟。
可以考虑的一个因素是,这可能会引导人们关注“较小的想法”,但正如我们之前承认的那样,有必要认识到想法如何随着时间的推移而演变,因为一个词只有在人们理解它时才有价值它想传达什么,因此我相信这个观点在维持艾伦·凯的最初目标和融入尼加德和达尔的对象系统的价值观之间找到了足够的平衡。
对于目前的定义文本,我已经可以满意了,这是我对本文提出的问题的回答,但我相信范式的完整定义应该包括它所代表的内容的“视角”程序的执行,以及与之相关的一组原则。
因此,我们可以说我们已经完成了一半,现在我们可以回到我之前给出的广泛定义列表,寻找哪些原则适合我们的观点,同时又不违背我们的基本愿景(专注于交换信息) .
为此,我们再次回到我们的主要来源,Smalltalk 的 OO 原则:
如果我们再次使用历史相关性标准,可能有人会说,由于这些术语今天不再使用(消息交换除外),我们应该考虑使用 4 个支柱,并且我再次相信,使用在这里采取和解的方法将是两全其美且不矛盾的:
有选择这5个原则的解释:
消息交换在OO的原始语境中是不可协商的事情,毕竟Alan Kay声称是范式的大思想,它最重要的概念,这就是为什么所有其他概念必须有一些东西处理它。
它在实践中的采用是相当可观的,因为具有历史相关性的语言,如 Self、Objective-C 和 Ruby 与这个概念保持着紧密的联系,并且 Ruby 本身被认为是当今的主流语言,构建了出色的应用程序除了拥有非常活跃的社区之外,它就像 github 本身一样。
我想说,除了继承和封装之外,它是最具有 OO 特性的概念之一,因为使用该术语的其他两个实例(有目的的笑话)将在 Actor 模型中,其中是一个数学模型形式逻辑,基本上与 Alan Kay 的思想几乎相同,但完全基于并发(像 OO 这样的东西对于你们 JS 开发人员来说是 100% 异步的)。
这是一个满足我们分析的所有标准的概念,因为正如 Nygaard 和 Dahl 所指出的,它几乎存在于实现该范式的所有语言中,即使是隐式的(如果它支持继承,支持也隐式支持多态性)。
它也与交换消息的想法非常一致,因为这是使用它的自然好处。此外,它出现在 Alan Kay 的定义中(尽管他说他更喜欢通用性这个术语),毕竟后期绑定是语言中存在的进程的名称
编程允许他们不将调用与特定代码关联起来,而是根据上下文执行它(在面向对象的情况下是接收消息的对象),这正是多态性的定义.
就公众认知而言,这将是所列出的 5 个概念中最重要的概念,甚至被 Bob 叔叔定义为 OO 的本质,而且,即使在不打算完全以面向对象编程的情况下,这被认为是构建一些想法(例如六边形架构或干净架构)的基本块的原则。
然而,这个概念并不是面向对象所独有的,它是一个更通用的概念,存在于多个范式中,通常具有同一语言中不同类型的实现。尽管如此,可以说特定的子类型多态性是 OO 所独有的,因为它是一种依赖于语言执行继承能力的类型。
如果您阅读过我们关于该主题的文章(是的,我们喜欢在这里讨论定义),您就会知道“本地数据保留,以及状态保护和隐藏”基本上是完整的定义封装,所以概念对齐方面,和之前的一样,这里100%遵循这个原则。
虽然有些语言没有提到封装作为原则,但这个概念在它们中甚至有一半存在,即拥有对象的事实(或者像Java和Self的情况一样,强调对象中字段的概念)表明它们有一种机制可以使数据及其函数(对象本身)仅在本地上下文中进行操作,另一方面,C++ 和 Eiffel 等语言提供了保护和隐藏表单中状态的机制访问修饰符 (C++) 或断言、前置条件、后置条件和不变量 (Eiffel)。在 Java 中,我们甚至有一篇关于面向对象的最著名的文章,其中详细讨论了封装的应用:为什么 getter 和 setter 是邪恶的。
所以我想说,这是一个经过时间考验已经非常成熟的原则,尽管它仍然会受到与多态性相同的批评,因为它不是一个专门与 OO 相关的概念,因为它可以使用模块(类似于单例对象)或闭包来实现它,因为它们可以充当穷人的对象,但是,就像多态性一样,该概念在面向对象中“具有独特的风味”应用,因为本地数据保留机制是对象,并且信息隐藏是通过访问修饰符发生的,这是一种与范式广泛相关的功能。
它不像其他 4 个支柱那样出现得那么多,但是,与封装类似,仍然可以隐式而不是显式地感受到它的存在,因为除了 Self 之外,所有提到的语言都有一种机制以类的形式进行数据抽象。
谈到自我的问题,他非常强调对象本身和信息的交换,我们可以利用这些来分析概念对齐的问题,在这种情况下,我会说编程通过消息交换,用更现代的话来说(尽管概念并不完全相同)将与“接口编程”相同,即仅使用抽象进行编程,而不用担心最终的实现实际上是什么就像 Alec Sharp 所著的《Smalltalk by Example: The Developer's Guide》一书中很好地描述的方法一样,它是“面向对象的编程方式”。
抽象与多态相结合的思想允许每个消息交换隐喻发挥作用,因为这个思想是没有办法仅通过查看消息来知道执行代码的结果是什么,之后它们都是抽象(就像在现代面向对象中读取接口的方法时你无法知道事物将如何执行一样),并且结果取决于在对象本身中找到的具体实现,因此执行可能会有所不同,具体取决于哪个对象响应该消息。
在所有原则中,我想说抽象是排他性标准中最弱的,因为数据抽象是一个通用原则,高于 Peter Van Roy 在他的《傻瓜编程范式》一文中所述的范式概念,尽管如此再次,我们处于与其他原则类似的情况,其中它使用类形式的极其特有的机制,这些机制被广泛认为是面向对象的功能,因此认识到许多人认为该范式仅限于使用类(甚至忘记了对象,更糟糕的是,忘记了过程中的消息)。
她来这里的目的与交换消息的目的相反,如果交换消息的公众感知得分较低,但概念对齐度最高,则继承对所选概念的概念对齐度最低(可以通过引用 Alan Kay 只是为 Smalltalk 添加了遗产,因为他并不真正知道它会被用来做什么,但认为它可能有用),但除了非常高的历史贡献之外,它还拥有最大的公众认知度。
首先,它是Simula的主要特性之一,在后Smalltalk时代,它被认为是OO的精髓,尽管在GoF发表组合而不是继承的思想后,这完全扭转了。
尽管如此,它是唯一与 OO 相关的概念,在许多情况下,它的存在足以将一种语言区分为面向对象的语言。唯一可能反对这一点的论据是 Hoare 的记录的想法,但正是它引发了 Simula 中的继承和产品类型,但这与继承是一个非常不同的主题,并且如果你们也面临着同样的问题和争议。
终于有了视角和原则,所以我们最终的定义是:
面向对象的程序被视为对象的网络,这些对象是领域概念的表示,通过消息交换进行通信,其目的是编程避免数据,专注于交互,以便消息可以携带几个意思。其原则是消息交换、多态、封装、抽象和继承。其总体结构类似于对世界真实或想象部分的行为的模拟。
无论如何,这是我对文章标题中提出的问题的最终答案,整个研究工作量很大,所以我希望这篇文章至少能教会你一些新东西,或者引发一些思考。
如果你同意或不同意我的定义,别忘了在评论中分享你的观点,我们下次再见!
屁股:累了支持
以上是毕竟,面向对象的定义是什么?的详细内容。更多信息请关注PHP中文网其他相关文章!