it-swarm.cn

是OOP很难,因为它不自然吗?

人们经常会听到OOP自然与人们对世界的看法相对应。但是,我强烈反对这一说法:我们(或至少我)从以下角度对世界进行了概念化: relationships我们遇到的事情之间,但OOP=的重点是设计单个类及其层次结构。

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

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

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

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

因此,我认为主流的OOP(基于类的单派遣))很难,因为它IS不自然且与如何人类思考世界,CLOS的通用方法更接近我的思维方式,但是,可惜,这不是普遍的方法。

考虑到这些问题,为什么/为什么发生当前流行的主流OOP=)?如何做才能废what它?

86
zvrba

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

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

    一个。 OO通常最适合当您的行为与行为所基于的状态密切相关,并且状态的确切性质是实现细节,但是无法轻易抽象出来时)例如:Collections类。

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

    c。当您具有易于声明式编写的东西,使得任何状态的存在都是可以轻松抽象的实现细节时,功能性才是最好的。示例:映射/减少并行性。

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

97
dsimcha

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

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

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

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

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

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

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

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

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

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

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

鉴于这些问题,为什么/为什么发生目前流行的主流OOP?

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

48
Péter Török

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

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

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

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

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

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

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

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

那里的很多东西(尤其是在遗留区域中)说是OO,否则不是。例如,有大量的C++代码没有实现OOD的图。

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

10
Matt Ellen

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

阅读OOP(Oper $ ===早期,Borland撰写的Pascal精简手册))上的第一本书,我对它的简单性和潜力感到惊讶(之前,我一直在使用Cobol,Fortran,汇编语言和其他史前的东西。)

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

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

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

7
Nerevar

一件事让我感到很难,当时我以为OOP是关于建模世界的想法。我以为,如果我做得不好,可能会有东西咬我(a事情要么是真的,要么是不是。)我很清楚假装一切都是对象或实体的问题,这使我对OOP中的编程非常不确定。

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

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

6
Pinochle

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

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

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

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

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

4
Caleb

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

4
SK-logic

[[〜#〜] edited [〜#〜]

首先,我想说的是,我从未发现OOP]比其他编程范例更难或更难。编程天生就是困难的,因为它试图解决现实世界中的问题,另一方面,当我阅读此问题时,我问自己:OOP“比其他范式更自然”吗?因此更有效吗?

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

另一方面,面向对象的支持者声称,尽管在系统的早期开发过程中OOP甚至可能比命令要花费更多的时间,但从长远来看,代码更易于维护和维护。由于数据和操作之间的紧密集成而扩展。

我主要使用OOP语言(C++,Java),但我经常感到使用Pascal或Ada可以提高工作效率,即使我从未在大型项目中尝试过它们。

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

[cut]

因此,我认为主流的OOP(基于类的单派遣))很难,因为它IS不自然且与如何人类思考世界,CLOS的通用方法更接近我的思维方式,但是,可惜,这不是普遍的方法。

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

我知道其他OO提案,其中多个对象接收一条消息,而不是仅一个,即几个对象在接收一条消息时起对称作用。是的,这似乎更笼统,也许更自然(限制较少)OOP对我来说是方法。

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

3
Giorgio

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

3
Marcin

这只是OOP错误的一部分。

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

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

3
hasen

停止寻找排他的OOP=范例,然后尝试使用一些JavaScript。

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

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

但是我不是单独用OOP=来做到这一点的,JS甚至不是“正确地” OOP=通过某些定义,我觉得很有趣。对,对于我认为更高级别的应用程序开发具有将范型弯曲到适合您的情况的能力,并且如果我们愿意的话,我们可以很好地模拟类。但是在这种情况下,我混合了功能(传递处理程序)左右)与OOP。

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

所以我想我想说的是:这不是switch语句的问题。它是混合搭配。问题是语言和时尚希望您相信这是一回事。初级的Java开发人员,例如,当他们认为自己默认情况下总是做得很好时,如何才能真正欣赏OOP?

3
Erik Reppen

我认为当人们尝试使用OOP代表现实)时会遇到一些困难。每个人都知道汽车有四个轮子和一个发动机。每个人都知道汽车可以Start()Move()SoundHorn()

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

2
Tom W

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

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

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

2
Trezoid

这是通过分类思考世界的自然方法。 OO大约是多少。OOP很难,因为编程难。

2
Tom Hawtin - tackline

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

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

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

O.O.P.和“一切都是列表或项目”范式被认为是“更自然”编程风格中的2种,正如我在某些人工智能课程中所记得的那样。

听起来很奇怪,“ O.O.P。是不自然的”,也许是您学习的方式,或者是关于O.O.P.的教导方式。是错误的,但不是O.O.P.本身。

1
umlcat

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

如果正确理解,OOP是关于黑匣子(对象),其上具有可以按下(方法)的“推动”按钮。类仅用于帮助组织这些黑匣子。

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

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

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会冻结。

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

1
Calmarius

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

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

另外,在实践中,决定是否在窗口或文本中放置show的问题在实践中几乎总是比理论上更加明确。例如,几乎所有GUI工具包都将容器add分组,而将窗口部件show分组。如果您尝试以另一种方式编写代码,即使抽象地思考这两个方法似乎可以互换,但原因很快就会变得显而易见。

1
Karl Bielefeldt

考虑到这些问题,为什么/为什么发生当前流行的主流OOP=)?如何做才能废what它?

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

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

1
Sean McMillan

看看由MVC模式发明者发明的 [〜#〜] dci [〜#〜] (数据,上下文和交互)。

DCI的目标是(引自Wikipedia):

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

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

0
Sire

人们经常会听到OOP自然对应于人们对世界的看法。但是我强烈反对这一说法(...)

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

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

鉴于OOP)的普遍误解以及对定义的OO)的敏感程度,这种说法进入了明智的领域。我在该领域已经有十多年了,我可以告诉您我花了很多年的时间来学习“主流OO”,因为我开始注意到它与早期创作者的目标有何不同(和劣等)。关于该主题的最新治疗方法,我将参考库克最近的工作:

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

鉴于这些问题,为什么/为什么发生目前流行的主流OOP?

也许是出于相同的原因QWERTY键盘变得流行,或者是DOS操作系统变得流行的相同原因。尽管它们具有某些特性,但它们只是乘着流行的交通工具而已,并且本身变得很流行。有时,类似但较差的事物被视为实际事物。

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

使用高级方法编写程序。使用OO=)方法编写相同的程序。显示前者在每个重要的方面(系统本身的属性和工程属性)都比后者更好。是相关的,如果将其应用于其他类型的程序,建议的方法也可以保持较高的属性质量,因此您必须进行严格的分析,并在必要时使用精确且可接受的定义。

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

0
Thiago Silva