因为不自然,OOP难吗?


86

人们常常可以听到,OOP自然对应于人们对世界的思考方式。但是我强烈不同意这种说法:我们(或者至少我)根据我们遇到的事物之间的关系来概念化世界,但是OOP的重点是设计各个类及其层次结构。

注意,在日常生活中,关系和动作主要存在于对象之间,这些对象本来是OOP中无关类的实例。这样的关系的示例是:“我的屏幕在桌子的顶部”;“我(一个人)坐在椅子上”;“道路上有汽车”;“我正在键盘上打字”;“咖啡机煮水”,“文本显示在终端窗口中”。

我们以二价(有时是三价,例如“我给你送花”一词)动词来思考,其中动词是对两个对象进行操作以产生某种结果/动作的动作(关系)。的焦点是关于动作,两个(或三个)[语法]对象具有同等的重要性。

与OOP相反,在OOP中,您首先必须找到一个对象(名词),并告诉它对另一个对象执行某些操作。思维方式从对名词进行操作的动作/动词转变为对名词进行操作的名词-好像一切都是被动或反身的声音所说的,例如,“文本正在终端窗口中显示”。或者也许是“文本在终端窗口上绘制自身”。

不仅焦点转移到了名词上,而且一个名词(我们称其为语法主语)比另一个名词(语法对象)具有更高的“重要性”。因此,必须决定是说terminalWindow.show(someText)还是someText.show(terminalWindow)。但是,当一个人真正表示show(terminalWindow,someText)时,为什么要给这些琐碎的决定加重负担却又没有任何操作后果呢?[结果在操作上无关紧要-在两种情况下,文本都显示在终端窗口上-但是在类层次结构的设计中可能非常严重,并且“错误”的选择可能导致复杂的代码和难以维护的代码。]

因此,我要指出,进行OOP(基于类,单派遣)的主流方法很困难,因为它是不自然的,并且与人类对世界的看法不符。CLOS的通用方法更接近于我的思维方式,但是,可惜,这不是普遍的方法。

鉴于这些问题,为什么/为什么发生当前流行的OOP方式如此流行?可以采取什么行动来废除王位呢?


OOP用于“编程”,是供编译器使用的。这不是以任何方式对现实世界建模的方法。在进行OOP教学时,通常会使用诸如动物类和矩形类之类的真实示例,但这只是简化概念的示例。不幸的是,编程语言和范式以非进化和非科学的方式“发生”。除了少数例外,语言设计过程通常是少数人最好的猜测之子!
NoChance 2012年

3
我不同意“ OOP的重点是设计单个类及其层次结构”这一说法。因为可能,它是OOP某些实现的重点,但是例如,我发现动态OOP语言通常没有大型层次结构,甚至没有类。好吧,面向对象的定义可能会在将来发生变化,甚至有一种尝试甚至可以更改对象wcook.blogspot.com/2012/07/proposal-for-simplified-modern.html
Azder,2012年

1
OOP正在标识系统中的对象,并基于这些对象构造类。并非相反。这就是为什么我也不同意“ OOP的重点是设计单个类及其层次结构”的原因。
Radu Murzea 2012年


1
我认为这是一个非常主观的问题,并且充满关于OOP以及“现实世界”是什么以及人们如何思考问题的怪异假设。最后,它甚至问:“还有什么方法可以废除它呢?” 这确实表明,OP对此有很强烈的意见。如果您对编程范例是“宗教的”,我想您不需要任何答案...您已经知道您想听什么。如果我第一次问这个问题的时候就知道了,我可能会投票关闭它……
西蒙·莱曼

Answers:


97

OOP对于某些问题是不自然的。这样的程序。所以功能。我认为OOP有两个问题确实使它看起来很难。

  1. 有些人的行为就像是编程的唯一方法,而所有其他范例都是错误的。恕我直言,每个人都应该使用一种多范式语言,并为他们当前正在处理的子问题选择最佳的范式。您的代码的某些部分将具有OO样式。有些将起作用。有些将具有直接的程序样式。有了经验,很明显哪种范例最适合:

    一种。OO通常最适合于您的行为与行为所依赖的状态密切相关,并且状态的确切性质是实现细节,但是状态的存在不能轻易抽象出来。示例:集合类。

    b。当您有一堆行为与任何特定数据没有强烈关联时,过程式方法是最佳选择。例如,也许它们对原始数据类型进行操作。在这里将行为和数据视为单独的实体是最容易的。示例:数字代码。

    C。当您具有易于声明式编写的东西,从而任何状态的存在都可以很容易地抽象出来的实现细节时,功能是最好的。示例:映射/减少并行性。

  2. OOP通常在大型项目中显示其有用性,在大型项目中,确实需要封装良好的代码段。在初学者项目中,这种情况不会发生太多。


4
我认为问题中的一个重点不是OOP是否自然,而是面向OOP的主流方法是否是最自然的OOP方法。(无论如何都是好的答案。)
Giorgio

11
“ OOP通常在确实需要封装良好的代码段的大型项目中显示其有用性。”:但这不是OOP的特定属性,因为对于命令式,功能式,...编程语言也有好的模块概念。
乔治

2
OOP确实位于过程/功能的不同轴上;它解决了如何组织和封装代码,而不是如何描述操作。(您始终将 OOP与执行范例结合在一起。是的,有OOP +功能语言。)
Donal Fellows

1
难道不能说OOP只是我们将程序性内容放入其中的盒子吗?
埃里克·雷彭

在OOP中,您仍然可以编写方法。是什么使OOP弱于过程编程?
Mert Akcakaya 2012年

48

恕我直言,这是个人品味和思维方式的问题。我对OO没什么问题。

我们(或者至少是我)根据遇到的事物之间的关系来概念化世界,但是OOP的重点是设计各个类及其层次结构。

恕我直言,事实并非如此,尽管这可能是一种普遍的看法。OO的发明者艾伦·凯(Alan Kay)始终强调对象之间发送的消息,而不是对象本身。消息,至少对我来说,表示关系。

注意,在日常生活中,关系和动作主要存在于对象之间,这些对象本来是OOP中无关类的实例。

如果对象之间存在关系,则根据定义它们是相关的。在OO中,您可以使用两个类之间的关联/聚合/使用依赖关系来表示它。

我们以二价(有时是三价,例如“我给你送花”一词)动词来思考,其中动词是对两个对象进行操作以产生某种结果/动作的动作(关系)。重点放在行动上,两个(或三个)[语法]对象具有同等的重要性。

但是它们在上下文中仍然具有明确定义的角色:主题,对象,动作等。“我给你花”或“你给我花”是不一样的(更不用说“花给我花了”): -)

与OOP相反,在OOP中,您首先必须找到一个对象(名词),并告诉它对另一个对象执行某些操作。思维方式从对名词进行操作的动作/动词转变为对名词进行操作的名词-好像一切都是被动或反身的声音所说的,例如,“文本正在终端窗口中显示”。或者也许是“文本在终端窗口上绘制自身”。

我不同意这一点。恕我直言,英语句子“ Bill,go the hell”在程序代码中bill.moveTo(hell)比而不是看起来更自然move(bill, hell)。实际上,前者实际上更类似于原始的主动语音。

因此,必须决定是说terminalWindow.show(someText)还是someText.show(terminalWindow)

同样,要求终端显示一些文本或要求文本显示终端是不同的。恕我直言,很明显哪个更自然。

鉴于这些问题,为什么/为什么发生当前流行的OOP方式如此流行?

也许是因为大多数OO开发人员对OO的看法与您不同?


15
+1代表直接提到对象之间的消息及其重要性,来自Alan Kay
Bunglestink 2011年

3
@zvrba,的确,还有其他面向对象的先驱,但这不在本文讨论范围之内。“最自然的事情是要求显示文本。” -现在您使用的是您声称在OOP中是如此“不自然”的被动语音。
彼得Török

5
@zvrba,您说“总是有一个“代理人”在做一些事情”,但抗议OO方法来识别和命名这些代理人(对象),并以该语言将其作为头等公民来对待。对我来说,这是对问题域进行建模的一部分-无论如何,您都需要进行这项工作,然后根据您的语言是否为面向对象,以另一种方式将生成的域模型映射为代码。
彼得Török

6
@zvrba,它本身不是面向对象的,而是决定不同对象的角色和职责的开发人员/设计人员。使用OO方法可能会产生好坏的领域模型和设计,就像使用刀可以为您提供一片精美的面包或流血的手指一样-仍然我们不应该怪罪刀,因为它只是一种工具。还要注意,模型中的概念/对象/代理是现实世界中事物的抽象,因此总是受限制和扭曲,仅关注特定的“有趣”方面。
彼得Török

6
@zvrba,汽车的确不会按照自己的意愿起步-就像Car对象start()只有在有人明确调用其方法时才会起步一样。
彼得Török

10

一些程序员觉得OOD很难,因为那些程序员喜欢思考如何为计算机解决问题,而不是思考如何解决问题。

...但是OOP的重点是设计各个类及其层次结构。

OOD并非如此。OOD旨在弄清事物的行为方式和相互作用。

我们以二价(有时是三价,例如“我给你送花”一词)动词来思考,其中动词是对两个对象进行操作以产生某种结果/动作的动作(关系)。重点放在行动上,两个(或三个)[语法]对象具有同等的重要性。

对OOD的关注始终是动作,动作是对象的行为。没有它们的行为,物体就什么也不是。OOD的唯一对象约束是一切都必须由某种事物来完成。

我认为做事比做事更重要。

但是,当一个人真正表示show(terminalWindow,someText)时,为什么要给这些琐碎的决定加重负担却又没有任何操作后果呢?

对我来说,这是同一回事,只是符号不同。您仍然必须确定谁是表演者,谁是表演者。一旦知道了,OOD就没有决定。Windows显示文本-> Window.Show(text)。

有很多东西(特别是在传统区域中)表示不是OO。例如,有大量的C ++代码未实现OOD图。

一旦您摆脱了解决计算机问题的观念,OOD就很容易。您正在为做事的事情解决问题。


10
我不完全喜欢OOD,因为我更喜欢思考如何解决问题。我不想考虑如何将问题域的自然语言转换为对象,消息,继承等外来世界。我不想发明不自然存在的分层分类法。我想用自然语言描述问题,并以最简单的方式解决它。而且,顺便说一下,世界不仅仅是由“做事的东西”构成的。您对现实的看法极为狭窄。
SK-logic

7
@Matt Ellen,我编写了一些程序来模拟不是“事物”并且没有“做”任何“东西”的实体的行为。任何不可变 实体都不做任何事情。任何数学纯函数都不会做任何事情-仅仅是从一组到另一组的映射,而这个世界主要由此类函数来描述。任何逻辑形式主义都不会“做”任何事情。是的,OOD不会对我有所帮助,因为我能够使用很多很多更强大的抽象和模型。回到原始的,有限的,有限的OOD将会严重阻碍我。
SK-logic

2
@Matt Ellen,是的,我希望看到引用支持这样奇怪的说法,即世界最好被视为“做事的事物”或“通过消息进行交互的对象”的集合。这是完全不自然的。接受任何科学理论(因为在这个阶段,它们都尽可能地接近对现实世界的建模),并尝试使用您的术语对其进行重写。结果将是笨拙和尴尬的。
SK-logic

4
@ Antonio2011a,没有一种编程或建模范例可以有效地覆盖所有可能的问题领域。OOP,功能,数据流,一阶逻辑等等,它们都是特定于问题领域的范例,仅此而已。我只是在提倡多样性和思想开放的方法来解决问题。将您的思想缩小到一个范式只是愚蠢的。en.wikipedia.org/wiki/Language-oriented_programming
SK-logic

3
@Calmarius为什么会让计算机编程更轻松?那真是愚蠢。必须付出更多努力的是人类。
马特·艾伦

7

也许我无法理解这一点,但是:

读了有关OOP的第一本书(90年代初,Borland编写的Pascal精简手册),我对它的简单性和潜力感到惊讶。(以前,我一直在使用Cobol,Fortran,汇编语言和其他史前语言。)

对我来说,很清楚:狗是动物,动物必须吃,我的狗是狗,所以它必须吃...

另一方面,编程本身固有地是不自然的(即人为的)。人的言语是人为的(不要怪我,我们都从别人那里学习了我们的语言,没有人认识发明英语的人)。一些科学家认为,人的思想是由他首先学习的语言形成的。

我承认,现代OO语言中的某些构造有些笨拙,但这是不断发展的。


1
从cobol到fortran,再到组装(及其余),您的工作到底是什么?
Rook

1
顺序错误。实际上,我一直是从Basic开始的,然后转移到Fortran,然后转移到Assembly和Cobol(是的,这是正确的顺序:首先组装)。我生命中的第一台计算机是一个“巨大的”大型机,内存为256kB,在其控制台上打字,并向打孔卡供电,因为我是计算机的操作员。当我成长为一名系统程序员之后,一个叫做PC-AT的可疑东西落在了我的办公桌上。因此,我沉迷于GW-Basic,Turbo-Pascal等。
Nerevar

1
我不是那个人。更多关于您的工作领域;因为我认识的人(真正的人)不多,涉及过COBOL(面向业务),fortran(科学领域),汇编程序(面向CS)以及其他人员。尽管如此,他们还是不是专业程序员。
Rook

1
毫无疑问:加入之前已决定使用语言方法的团队和项目。以及对他们使用的工具的好奇心。
Nerevar

6

让我感到难过的一件事是,认为OOP就是要对世界建模。我以为,如果我做错了,可能会有些东西咬我(事情是对的还是不对的)。我非常意识到假装一切都是对象或实体的问题。这使我对OOP中的编程感到非常的尝试和信心不足。

然后,我阅读了SICP,并重新认识到它实际上是关于数据类型和控制对它们的访问。我已经解决的所有问题都是因为它们基于错误的前提,那就是在OOP中您正在建模世界。

我仍然惊叹于这种错误前提给我带来的巨大困难(以及我如何迷恋它)。


感谢您指出尝试建模世界的危险。
肖恩·麦克米伦

4

是的,OOP本身是非常不自然的-现实世界并非完全由等级分类法构成。它的一些小部分是由这些东西组成的,而这些部分是唯一可以用OO充分表达的东西。所有其他自然不能适应这种琐碎而有限的思维方式。了解自然科学,了解发明了多少种不同的数学语言,以便以最简单或至少可理解的方式表达现实世界的复杂性。而且几乎没有一个可以轻松地翻译成对象和消息的语言。


5
嗯,这对于试图精确描述现实世界的任何形式表示法都同样适用。
彼得Török

1
@PéterTörök,正是我的意思。没有一种形式主义可以涵盖所有内容。您必须全部使用它们,因为它们令人恐惧。这就是为什么我相信面向语言的编程的原因-它允许将各种通常不兼容的形式主义引入到坚实的代码实体中。
SK-logic

1
一切都可以归类为分层分类法。诀窍在于提出有意义的方案。通常涉及多重继承。软件与现实世界之间的最大区别是,在现实世界中,我们经常不得不推断或发现分类方案;在软件中,我们发明了它们。
Caleb

1
通过使用“层次分类法”之类的术语,我认为您正在考虑继承。继承确实很难推理。这就是为什么人们建议使用合成而不是继承。
Frank Shearar 2011年

1
@弗兰克:现实世界中有许多类型的层次分类法,其中继承只是一种。正确地完成所有这些工作需要比OOP更好的工具(例如,本体论推理),并给哲学家造成了数千年的
Donal Fellows

4

我们(或者至少是我)根据遇到的事物之间的关系来概念化世界,但是OOP的重点是设计各个类及其层次结构。

您是从(IMO)开始的错误前提。可以说,对象之间的关系比对象本身更重要。这些关系提供了面向对象的程序结构。继承(类之间的关系)当然很重要,因为对象的类决定了该对象可以做什么。但是,由各个对象之间的关系决定了对象在类定义的范围内实际执行的操作以及程序的行为。

首先,面向对象的范式可能会很困难,这不是因为很难思考新的对象类别,而是因为很难预见对象图并了解它们之间的关系,特别是当您没有对象时。描述这些关系的方式。这就是设计模式如此有用的原因。设计模式几乎完全是关于对象之间的关系的。模式既为我们提供了可用于在更高层次上设计对象关系的构造块,又为我们提供了用于描述这些关系的语言。

在现实世界中工作的创意领域也是如此。任何人都可以把一堆房间拼在一起,称之为建筑。房间甚至可能已经配备了所有最新的装备,但并不能使建筑正常工作。建筑师的工作是根据使用这些房间的人的需求和建筑物环境优化这些房间之间的关系。从功能和美学的角度来看,正确建立这些关系是使建筑工作的原因。

如果您不习惯OOP,建议您多考虑一下您的对象如何组合在一起以及它们的职责如何安排。如果您还没有阅读过,请阅读有关设计模式的信息-您可能会意识到,您已经了解了所阅读的模式,但是给它们起名字将使您不仅可以看到树木,而且还可以看到看台,林木,灌木丛,森林,树林,林地,最后是森林。


3

这只是OOP错误的一部分。

本质上,职能成为二等公民,这是不好的。

现代语言(ruby / python)不会遇到这个问题,并提供作为一流对象的功能,并允许您在不构建任何类层次结构的情况下编写程序。


OOP对我来说似乎很自然,实际上我很难以其他任何方式考虑编程任务。尽管如此,多年来,我逐渐了解到,OOP倾向于过分强调名词而不是动词。这从2006年的咆哮帮助我理解这种区别:steve-yegge.blogspot.com/2006/03/...
吉姆在得克萨斯州

3

OOP不难。很难很好地使用它的原因是对它的好处有一个浅浅的了解,在这种情况下,程序员会听到随机的格言,然后屏住呼吸重复自己,以得到神圣的四人帮,加福的马丁·福勒(Martin Fowler)或他们一直在读书的人。


3

已编辑

首先,我想说的是,我从未发现OOP比其他编程范例更难或更难。编程本质上是困难的,因为它试图解决现实世界中的问题,并且现实世界极其复杂。另一方面,当我读到这个问题时,我问自己:OOP是否比其他范式“更自然”?因此更有效吗?

我曾经找到一篇有关命令式编程(IP)和面向对象的编程(OOP)之间的比较研究的文章(希望我能再次找到它,以作为参考)。他们基本上测量了在不同项目中使用IP和OOP的专业程序员的生产力,结果是他们没有看到太大的差异。因此,他们声称两组之间的生产率没有太大差异,而真正重要的是经验。

另一方面,面向对象的拥护者声称,尽管在系统的早期开发中,OOP可能花费比必不可少的时间,但从长远来看,由于数据和数据之间的紧密集成,代码更易于维护和扩展。操作。

我主要使用OOP语言(C ++,Java)工作,但是我常常感觉即使使用Pascal或Ada,即使从未在大型项目中试用过它们,我也可以保持生产力。

与OOP相反,在OOP中,您首先必须找到一个对象(名词),并告诉它对另一个对象执行某些操作。

[切]

因此,我要指出,进行OOP(基于类,单派遣)的主流方法很困难,因为它是不自然的,并且与人类对世界的看法不符。CLOS的通用方法更接近于我的思维方式,但是,可惜,这不是普遍的方法。

当我更仔细地阅读了最后一段时,我终于理解了您的问题的要点,我不得不从头开始重写我的答案。:-)

我知道其他面向对象的提议,其中多个对象接收一条消息而不是仅一条消息,即,多个对象在接收一条消息时起着对称的作用。是的,对我来说,这似乎是一种更通用,更自然(不太严格)的OOP方法。

另一方面,可以使用“单个调度”轻松地模拟“多个调度”,并且更易于实现“单个调度”。也许这就是“多重派遣”尚未成为主流的原因之一。


3

停止寻找专有的OOP范例,然后尝试一些JavaScript。

我目前有一种解决方案,其中UI对象在事件驱动的界面下运行。也就是说,我将拥有一个看起来像是典型的公共方法,该方法在被触发时会导致内部定义的操作。但是,当它被触发时,真正发生的是我在对象本身上触发了一个事件,并且该对象内部的预定义处理程序做出了响应。该事件和可以附加属性的事件对象可以传递给任何其他侦听器,任何关心侦听的事物都可以听到。您可以直接侦听该对象,也可以大致侦听该事件类型(事件也会在该通用对象上触发,该对象由工厂构建的所有对象都可以侦听)。因此,举例来说,现在我有了一个组合框,您可以从下拉列表中选择一个新项目。

如果愿意,(我很惊讶地发现我通常不想要-当您看不到事件来自何处时,这是一个易读性问题),您可以将对象完全耦合,并通过传递的事件对象建立上下文。无论如何,您仍然可以通过注册多个响应者来回避单派。

但是我并不是仅靠OOP来做到这一点,而且从某些定义上来说,JS甚至不是“适当的” OOP,我觉得这很有趣。在我看来,对于更高级别的应用程序开发,适当的是,有能力将范式转变为适合您的情况的一切,如果我们愿意,我们可以很好地模拟类。但是在这种情况下,我将功能方面(传递处理程序)与OOP混合在一起。

更重要的是,我的感觉很强大。我不是在考虑一个对象作用于另一个对象。我基本上是在确定对象关心的事情,为它们提供所需的工具,以便将它们整理出来,然后将它们放入混合器中,并使它们相互反应。

所以我想我想说的是:这不是switch语句的问题。它是混合搭配。问题是语言和时尚希望您相信这是一回事。举例来说,初级Java开发人员如何在默认情况下始终正确地进行操作时真正欣赏OOP?


2

向我解释的方式是用烤面包机和汽车。两者都有弹簧,所以您会有一个“弹簧”物体,它们的大小,强度和其他功能都不同,但是如果您有很多轮子,它们都将是“弹簧”,然后将这个比喻扩展到汽车上(显然,车轮,再加上方向盘等),这很有道理。

然后,您可以将该程序视为一个对象列表,然后将其可视化会比“这是一堆可以处理事情的列表,因此不像您之前看到的指令列表”要简单得多。

我认为OOP的真正问题在于如何向人们解释。通常(在我的uni类中)我看到它的解释是说“这是关于许多类的事情,而您可以创建小对象”,这一切都会使很多人感到困惑,因为它使用的是本质上抽象的东西用术语来解释这些概念,而不是人们在5岁时与乐高玩耍时已经掌握的具体思想。


2
弹簧有数以百万计的形式,所有形式都有相似的功能。我会说这是函数式编程的完美示例。
l0b0 2011年

2

这是通过分类思考世界的自然方法。或多或少是面向对象的。因为编程困难,所以OOP困难。


但是,您是否根据某些对象具有共同的属性或共同的行为进行分类?所有有名字和姓氏的人都是人吗?走路的动物都是动物吗?
zvrba 2011年

当涉及分类时,能够执行某种行为是一个属性。斑马和马可以繁殖,但后代是杂种。除非您知道它们不是同一物种,否则很难根据拥有的交配功能来预测此结果。
JeffO 2011年

1
@zvrba:我对评论中提出的问题的回答是it doesn't matter。每个有名字和姓的东西都是每个程序中只关心人的人。对于任何不了解人或非人的程序,它都是IHasNameAndSurname。对象只需要解决眼前的问题。
汤姆W

@Jeff O即使在相同的物种/品种/种群中,也存在变异,没有理想的(必要的)例子。因此,是的,OO并非自然界那样,但这很适合人类的自然思维。
汤姆·哈特芬

2

我认为当人们尝试使用OOP表示现实时会遇到一些困难。大家都知道汽车有四个轮子和一个引擎。每个人都知道汽车可以Start()Move()而且SoundHorn()

当我意识到我应该一直停止尝试这样做时,我的头上发出了一声光。对象不是与其共享名称的东西。一个对象是(即应该是)与问题范围相关的足够详细的数据分区。它ought具有解决问题所需的确切功能,没有更多也没有更少。如果使一个对象负责某种行为导致代码行多于某些含糊的第三方(某人可能称其为“ poltergeist”)的行为,则该恶意行为者会赢得其筹码。


1

为了管理复杂性,我们需要将功能分组到模块中,这通常是一个难题。就像关于资本主义的老话一样,OOP是在那里最糟糕的组织软件的系统,除了我们已经尝试过的所有其他方法。

尽管经常对将两个名词归为一组进行歧义,但我们仍将名词内部的交互分组,是因为名词的数量恰好适用于可管理的大小类别,而按动词分组往往会产生非常小的小组(例如一次性),或者非常大的小组(例如show)。按名词分组时,诸如继承之类的重用概念也会更容易实现。

而且,实际上在实践中比在理论上更加清楚地决定是在窗口中显示还是在文本中显示。例如,几乎所有GUI工具包组都随容器一起添加,但随窗口小部件一起显示。如果您尝试以另一种方式编写代码,即使抽象地思考这两个方法似乎可以互换,但原因很快就会变得显而易见。


2
您见过合适的 模块系统吗?怎么说OOP是最好的呢?SML模块的功能要强大得多。但是,即使没有一点OOP提示,即使是Ada包也足以满足大多数情况。
SK-logic

@ SK-logic,我认为您已经迷上了过于精确的定义。对于OOP,我不是指,而是指对按其操作的“名词”在逻辑上对“动词”进行分组,并能够根据碰巧对其进行操作的特定名词重用和专门化这些动词。类碰巧是最著名的实现,但不是唯一的实现。我承认SML模块是无知的,但是当我查找它时,我看到的第一个示例是一个队列的实现,该队列的实现可以来自任何OO设计手册,并进行了语法更改以使其能够运行。
Karl Bielefeldt

不幸的OOP对于不属于它的东西给予过多的赞誉根本是不公平的。模块是一个伟大的发明。一流的模块很棒。但是OOP与它们完全无关。某些OOP语言采用了某些模块功能(最著名的是名称空间),但是模块比类具有更通用,更强大的概念。您说过课程是“最好的”,这与事实相去甚远。一流的模块要好得多。而且,当然,类型系统比带有子类型的OO不仅仅是一个OO。
SK-logic

1
“就像关于资本主义的古话一样,OOP是在那里组织软件的最糟糕的系统,除了我们尝试过的其他一切。”:也许我们没有花足够长的时间尝试。:-)
乔治

1
我认为您的意思是“民主”:quotationspage.com/quote/364.html
nicodemus13

1

没有。有几种使用编程来解决问题的方法:功能,过程,逻辑,OOP等。

在现实世界中,有时人们使用功能范式,有时我们使用过程范式,依此类推。有时我们混在一起。最终,我们将它们表示为一种特定的编程风格或范例。

LISP中还使用了“一切都是列表或项目”范式。我想提一下与函数式编程的不同之处。PHP在关联数组中使用它。

我记得在某些人工智能课程中,OOP和“一切都是列表或项目”范式被认为是MORE NATURAL编程风格中的两种。

对于我来说,听起来很奇怪,“ OOP不是自然的”,也许您的学习方式或关于OOP的学习方法是错误的,但不是OOP本身。


1

鉴于这些问题,为什么/为什么发生当前流行的OOP方式如此流行?可以采取什么行动来废除王位呢?

OOP之所以受欢迎,是因为它提供了比以前流行的过程语言更高的抽象级别来组织程序的工具。使一种语言具有方法内部的过程结构以及围绕它们的面向对象的结构也相对容易。这使已经知道如何以编程方式进行编程的程序员可以一次选择一种面向对象的原理。这也导致了很多只面向对象的OO程序,这些程序是包裹在一两个类中的过程程序。

要废除OO,请构建一种语言,使它可以轻松地从大多数程序员今天所了解的内容(大多数是带有一点OO的过程)逐步过渡到您喜欢的范例。确保它提供了方便的API来执行常见任务并对其进行了很好的推广。人们很快就会用您的语言制作“仅X名”程序。然后,您可以预期人们要花很多年才能熟练完成X。


OP并不认为OO一般而言是不好的,应该予以废除,但“目前主流的OOP方式”并不是最自然的方式(与“多次派发”相比)。
乔治

OP似乎也过于专注于定义类型层次结构,而最好的OO程序往往更依赖于接口和组合。如果“多调度”为X,那么使人们逐渐学习与多调度相关的技能的语言仍然是更改环境的关键。
肖恩·麦克米兰

1

我认为OOP和OOP语言也有问题。

如果正确理解,OOP就是关于黑匣子(对象)的黑匣子(对象)上有可以按下(方法)的按钮。上课只是为了帮助组织这些黑匣子。

一个问题是程序员将按钮放在错误的对象上。终端不能在其自身上显示文本,文本也不能在其自身上显示文本。可以执行此操作的操作系统的窗口管理器组件。终端窗口和文本只是一个被动实体。但是,如果我们以这种方式思考,我们就会意识到大多数实体是被动的事物,而实际上只有很少的对象可以做任何事情(或者仅仅是一个对象:计算机)。确实,当您使用C时,将其组织到模块中,这些模块代表的对象很少。

另一点是,计算机只是按顺序执行指令。假设您有个VCR和一个Television对象,您将如何播放视频?您可能会这样写:

connect(television, vcr);
vcr.turnOn();
television.turnOn();
insert(vcr, yourFavoriteCasette);
vcr.play();
while (vcr.isPlaying()) {} // Wait while the VCR is playing the casette.
vcr.eject();
vcr.turnOff();
television.turnOff();

这很简单,但是您至少需要3个处理器(一个或多个):一个扮演您的角色,第二个是VCR,第三个是电视。但是通常您只有一个核心(至少不足以容纳所有对象)。在大学里,我的许多同学不了解为什么按钮执行昂贵的操作时GUI会冻结。

因此,我认为面向对象的设计可能很好地描述了这个世界,但这并不是计算机的最佳抽象。


0

看一下MVC模式的发明者发明的DCI(数据,上下文和交互)。

DCI的目标是(引自Wikipedia):

  • 在对象(名词)上方,赋予系统行为一流的状态。
  • 将用于快速更改系统行为(系统做什么)的代码与用于缓慢更改域知识(系统是什么)的代码干净地分开,而不是将两者合并在一个类接口中。
  • 支持接近人们思维模式的对象思维方式,而不是阶级思维方式。

这是作者的一篇好文章,如果您想看一些代码,这是一个小的示例实现(.NET)。它比听起来容易得多,而且感觉很自然。


0

人们常常可以听到,OOP自然对应于人们对世界的思考方式。但我强烈不同意这一说法(...)

几十年来,它在书本和其他地方被传播,我也不同意。尽管如此,我认为Nygaard和Dahl就是这样说的,我认为他们关注的是与当时的替代方案相比,设计仿真的难易程度。

(...),但是OOP的重点是设计单个类及其层次结构。

鉴于对OOP的普遍误解以及OO对定义的敏感程度,这一主张进入了明智的领域。我在该领域有十多年的经验,从事行业工作和有关编的学术研究。语言,我可以告诉您,我花了很多年的时间来学习“主流OO”,因为我开始注意到它与早期创作者的目标有何不同(和劣等)。对于主题的现代,最新的处理,我将参考库克最近的工作:

“关于“对象”和“面向对象”的简化,现代定义的提案 http://wcook.blogspot.com.br/2012/07/proposal-for-simplified-modern.html

鉴于这些问题,为什么/为什么发生当前流行的OOP方式如此流行?

也许是因为QWERTY键盘变得流行,或者是DOS操作系统变得流行。尽管物有所值,但乘上流行的车辆只是顺风顺水,它们本身就变得很流行。有时,某些事物的相似但较差的版本被视为实际事物。

可以采取什么行动来废除王位呢?

使用高级方法编写程序。使用OO方法编写相同的程序。说明在重要的各个方面(系统本身的属性和工程属性),前者的属性都比后者好。表明所选程序是相关的,并且如果将其应用于其他类型的程序,则所提出的方法可以保持高质量的属性。进行严格的分析,并在必要时使用精确且可接受的定义。

最后,与我们分享您的发现。


-1

以Java为例:对象是一种抽象瓶颈,大多数“事物”要么严格是对象的子组件,要么将对象用作其子组件。在这两种类型的事物之间的整个抽象层中,对象必须具有足够多的用途-多用途意味着它们没有体现任何隐喻。特别是Java使对象(&类)成为您调用/调度代码的唯一层。坦率地说,对象所包含的大量内容使它们过于复杂。对它们的任何有用的描述都必须限制为某种特殊形式或受限形式。

继承和接口层次结构是将对象用作子组件的“事物”。这是描述对象的一种专门方法,而不是获得对对象的一般理解的方法。

可以说“对象”具有或具有许多东西,因为它们是多用途抽象,在“ OO语言”中或多或少是通用的。如果它们用于包含本地可变状态或访问某些外部世界状态,则它们看起来非常像“名词”。

相反,表示过程的对象(例如“加密”或“压缩”或“排序”)看起来像“动词”。

一些对象用作它们的命名空间,例如,在Java中放置“静态”函数的位置。

我倾向于同意这样的论点,即Java在对象方法调用上过于繁重,而在对象上进行分派。这可能是因为我更喜欢Haskell的类型类来控制调度。这是一个调度限制,是Java的功能,但不是大多数语言,甚至不是大多数OO语言。


-3

我目睹并参加了许多有关OOP的在线辩论。OOP的支持者通常不知道如何编写适当的过程代码。可以编写高度模块化的过程代码。可以将代码和数据分开,并确保函数只能写入其自己的数据存储区。可以使用过程代码来实现继承的概念。更重要的是,过程代码更苗条,更快,更容易调试。

如果您使用严格的命名约定构建单文件模块,则过程代码比OO更易于编写和维护,并且执行相同或更多且更快。并且不要忘记,当您的应用程序运行时,无论您的脚本中有多少个类,它始终是过程性的。

然后,您遇到了像PHP这样的语言的问题,这些语言并不是真正的面向对象的,而是依靠黑客来伪造诸如多重继承之类的东西。影响语言方向的大人物已将PHP变成了不一致规则的拼凑而成,这些规则对于其最初的意图而言已经变得太大了。当我看到开发人员为过程模板语言编写了巨大的模板类时,我禁不住笑了。

如果将正确编写的OO代码与错误编写的过程代码进行比较,那么您总是会得出错误的结论。很少有项目需要面向对象的设计。如果您是IBM并管理着一个巨大的项目,需要由多个开发人员维护多年,请使用面向对象。如果您正在为客户编写小型博客或购物网站,请三思。

要回答最初的问题,OOP很难,因为它不解决现实生活中的编程难题,而没有采用比实际复杂100倍的解决方案。对于许多编程问题,最强大的解决方案之一是明智地使用全局数据。然而,新浪潮大学的毕业生会告诉你,这是一个很大的禁忌。仅当您笨拙的编程兔子时,全球可用的数据才是危险的。如果您有一套严格的规则和适当的命名约定,则可以将所有数据全局化。

任何面向对象的程序员都必须知道如何在汇编器中编写象棋应用程序,以实现最大可用内存16K,这是一个强制性要求。然后,他们将学习如何修剪脂肪,减少懒惰并产生巧妙的解决方案。

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.