基于原型的面向对象编程相比于基于类的面向对象编程有哪些优势?

44
为什么基于类的面向对象编程比基于原型的面向对象编程更受欢迎?学校里是否会教授后者?尽管Javascript是基于原型的,但大多数人在使用它时更倾向于函数式编程或通过模拟类的系统来使用。
我知道Sun公司曾经对Self进行过一些研究 - 是否有其他关于原型式面向对象编程的知识来源?最好是自学可得的。
我找到了一本包含论文的书:《基于原型的编程:概念、语言和应用》。
有人读过这本书吗?

--

所以我为给我提供最多答案的那个人提供了赏金。尽管如此,我仍然不是很满意。我希望能听到更多技术方面的回答。也许我没有表达清楚。


https://developer.mozilla.org/en/JavaScript/Guide/Details_of_the_Object_Model - pramodc84
这场辩论难道就此结束了吗?我总结了一篇有趣的论文。简而言之,基于类的世界观比原型的更有缺陷。因此,我们需要小心谨慎。以下是摘要链接:http://carnotaurus.tumblr.com/post/3248631891/class-based-javascript-or-not - Phil C
基于类的面向对象编程在历史上比基于原型的面向对象编程先出现,因此现在被广泛使用。在Javascript出现之前,替换这个概念被证明是不切实际的。预计学校将按照世界范围内使用该风格编写的代码量来教授基于原型的面向对象编程。下面的一些答案将基于原型的面向对象编程与动态继承混淆了。 - blueberryfields
请参阅程序员社区上与语言无关的“基于原型的面向对象编程相对于基于类的面向对象编程有哪些优势?”(What are the advantages of prototype-based OOP over class-based OOP?)相关的内容。 - Bergi
7个回答

23
原型继承的优点在于,它可以通过简单的原型链操作潜在地允许花哨的元编程。这是一个相当学术性的优点,因为99%的时间元编程都不是正确的答案。例如,你可以使用一种特殊的DSL,在本地离线时通过原型交换透明地切换到本地SQLite备份,并在联机时切换到基于REST的服务器存储的JavaScript键值观察器样式数据操作层。我不确定这是否是最好的方法,但这是我晚上能想出来的最好办法了。这不是你通常想在项目代码中做的事情,因为这种间接性会让你在多个层面上进行调试,但是当你将其保留在库中时,它并不那么糟糕。
另一个不太有用的优点是,它允许你设计自己的类系统。我说不太有用是因为几乎所有的JavaScript库都有自己稍微不兼容的方法来组合“类”。
有很多人回复说他们混淆了继承模型和实施该模型的语言。JavaScript具有动态和弱类型的特点,因此很难工具化,这与它是一种原型语言无关。

通过JavaScript的实现,您无法切换原型对象。它只是将实际原型对象从SQLite更改为REST吗? - Steve Rowe
是的。如果您通过save()函数进行所有技巧操作,您可以将SQLite save()替换为REST save():
rest_save = function(){return "REST"} sql_save = function(){return "SQL"} Storage = function(){/初始化等/} Storage.prototype.save = rest_save my_obj = new Storage() my_obj.save() "REST" Storage.prototype.save = sql_save function() my_obj.save() "SQL"
通过使用所有主要js库中可用的更新/合并函数,可以轻松地对整个对象执行此操作。不是“真正”的交换,但它可能很有用。
- Karl Guertin
11
我讨厌这些评论没有换行。 - Karl Guertin
2
JavaScript不是弱类型语言,它是强类型语言。你把弱类型和动态类型混淆了... - Angel O'Sphere
3
http://en.wikipedia.org/wiki/Weak_typing -> 明显是弱类型。而且在这里描述中也有提到:http://en.wikipedia.org/wiki/JavaScript。我认为你混淆了一件事情,就是你可以同时拥有动态和弱类型的语言,这正是JS所具备的。它绝对不是强类型的。 - Oscar Godson

19

如果你正在寻找有人指出每种编程方式的优缺点,并以此解释它们流行的原因,我认为你犯了一个谬误,这种谬误在技术领域非常普遍,即流行度与某种绝对质量标准有关。

事实上,真相要平淡得多 - 基于类的面向对象编程之所以流行,是因为Java使用经典的面向对象编程方式,Sun花费了数百万美元和很长时间来建立Java的流行度 - 确保人们知道它在企业中得到成功应用,在大学广泛教授,并且出现在高中AP测试中。

原型/经典面向对象编程只是组织思想的不同方式。您可以在不支持其本地实现的语言中实现任何一种(例如PythonJava,另外还有JavaScript)。

在传统面向对象编程中,你需要为你的对象定义一个抽象的类层次结构,然后实际上是通过这些类的实例来进行工作。而在原型继承中,则是创建了一个对象实例层次结构。虽然我想这在两个派别中都可能有点异端,但我认为你可以将两者混合使用...

1
我只是好奇是否有什么让基于原型的面向对象编程更具挑战性的因素,主要想知道在创建复杂软件时会有什么问题。我并不是说其受欢迎程度基于范式的质量,但这可能是其中一个原因。 - egaga
但是我想知道的是,原型基础的面向对象编程是否在任何地方被教授?如果是的话,我会对讨论如何以这种方式设计程序的材料感兴趣。 - egaga
3
基于原型的编程方式之所以强大,也是因为它具有危险性,你可以随时修改任何东西,并且会影响到所有相关内容。这就像是对全局变量的旧论点,你永远不知道谁在干涉什么。正因为如此,你必须非常小心,以免触及任何人的利益,但它也允许你做一些在其他语言中极其困难或不可能完成的事情(可以说是有充分理由的)。 - Orclev
1
@Orclev:那是完全没有关联的,并且不正确。例如,在ECMAScript 5中,您将能够“冻结”对象,确保它们以后不会被修改。@egaga:我只有作为罗格斯大学本科生的经验,并且在那里没有人教授任何接近原型继承的东西(有很好的理由-大学课堂上有更难教的东西,小语言范例可以自己学习)。 - Andrey Fedorov
在大多数情况下,对于大多数编程语言来说,在类基础系统之上实现基于原型的系统是极其低效的。然而,反过来则往往不成立。 - blueberryfields
显示剩余5条评论

12

这个问题引起了我的兴趣,于是我回去阅读了一些关于这个概念的原始论文。看起来这个概念在20世纪80年代中期开始流行于Smalltalk世界,但最终成为Self的创始原则之一。更晚期,Javascript也采用了它。

论文中提出的观点是,原型编程更容易学习。除了学习外,实际上没有提出其他技术益处。所有论文都解释了它和基于类的语言一样表达能力强,但更容易学习。人们天然地以具体方式思考事物而不是抽象的。我们想到的是动物园里看到的大象,而不是一个普通的“大象”。当我们看到其他大象时,我们将它们归类为与第一个大象的差异。原型编程语言促进了这种思考方式。将其视为差分编程。

这是使用它作为语言的充分理由吗?也许。自从这个想法首次开始发酵以来的25年里,我认为像基于类的OO这样的抽象概念并不难学习。另一方面,也许有需要一种更容易使用的蓝领编程语言(如Javascript),这可能是实现这一目标的方式。

如果感兴趣,你可以从这篇关于self的论文开始了解。


很高兴看到这个问题引起了一些兴趣!谢谢 :) - egaga

12

我不知道确切的原因,但是以下是我的理由:

我认为这个争论与动态和静态的区别相同,类是对象的静态定义,可以轻松地知道从对象中期望什么,它还帮助语言工具具有适当的智能感支持和文档,因为您可以轻松知道对象中的不同成员和方法,另一个是具有在类中声明私有成员的不同范例,这在原型范例中无法实现。

原型范例不错,但缺乏提供关于对象中方法和成员的信息的能力,这使得工具更难以使用,并且对于动态类型编程更有意义。


2
没错。静态语言需要类来让编译器知道期望/禁止什么。动态语言不需要它们,因此使用原型更方便。 - Javier
同意。然而请注意,虽然Javascript本身支持基于原型的继承,但使用闭包实现一些面向对象的特性并不难。例如,你可以很容易地获得真正保护私有方法和变量的功能。Dustin Diaz关于这个主题的书籍非常出色:“Pro Javascript Design Patterns”(http://jsdesignpatterns.com/)。事实仍然存在,对于这样的动态语言来说,工具链是困难的。由于Javascript是如此灵活,因此很难让开发环境知道你正在使用哪些继承模式。 - Eric Nguyen
4
我不同意“基于原型的对象缺乏提供有关对象中方法和成员的信息能力”的说法。与基于类的对象相反,在运行时很容易枚举。 - Thevs
此外,在基于原型的语言中,您可以将代码解释为数据,将数据解释为代码。这是相对于静态基于类的语言的一个巨大优势。这就是为什么大多数JavaScript程序员反对在ECMA 4标准中引入静态类的原因。 - Thevs
1
实际上,编写一种静态类型的基于原型的语言是可能的。 - Eva

5

5

这里有很好的解释,是关于基于原型的编程的批评。


3
我认为区别在于(原型)语言赋予程序员的权力动态不同。JavaScript,就像LISP一样,几乎无限地赋予了程序员权力。这种权力只受程序员责任和自信水平的限制。因此,这个讨论和静态类型与无类型的讨论一样古老。如果你认为自己的编程能力和自律足够强大,那么可以采用原型风格。
用一个著名的说法改写:
“天才做他想做的事情(读:基于原型),而才华横溢的人做他能做的事情(读:基于类)。”

1
但是你说的这种力量是什么?那就是我想要的。 - egaga
4
大多数情况下,这种能力就像是给自己的脚开枪。静态类型(以及类似的概念)旨在防止程序员误操作。这种语言有意让危险的事情变得更难实现。你可以仅使用非静态类型和基于原型的面向对象系统就能创造惊人的东西,但同样地,你也可能会做一些真的很糟糕的事情。 - Orclev
2
它是让你在程序中构建任何想象的力量。它仅受你的想象力限制。有时候幻想可能够疯狂 :) - Thevs
1
我非常喜欢这个答案,尽管它不是非常技术性的。它以一种时尚的方式很好地总结了整件事情 =) - BYK
@Orclev:为什么程序员必须“拯救自己”?你要么是程序员,要么不是。 :) 你要么对自己的工作负责,要么不负责。 - Thevs
1
是的,我也倾向于这样认为,并且我喜欢基于原型的面向对象编程,但同时(特别是在企业环境中),即使您能够编写正确的代码,您旁边的人可能不行,在这种情况下,设置一些障碍来阻止糟糕的代码并不一定是坏事。理想情况下,当然是应该解雇写糟糕代码的笨蛋,但我们有时候看到了这种情况。 - Orclev

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接