面向对象编程有什么意义?

126
据我所知,尽管在面向对象编程(OOP)教育、语言和工具方面花费了无数百万或十亿美元,但OOP并没有提高开发人员的生产力或软件可靠性,也没有减少开发成本。很少有人严格意义上使用OOP(很少有人遵守或理解诸如LSP等原则);人们采用建模问题域的方法往往缺乏一致性和一致性。太常见的是,类仅仅被用作其语法糖;它将记录类型的函数置于自己的小命名空间中。
我为各种应用程序编写了大量代码。虽然替代子类型在应用程序中发挥了重要作用,但这些情况相当特殊。总的来说,尽管人们口头上经常谈论“重用”,但现实是,除非一段代码 完全 满足您的需求,否则很难进行成本效益的“重用”。设计可扩展类以正确方式非常困难,因此扩展的成本通常非常高,以至于“重用”根本不值得。
在许多方面,这并不让我感到惊讶。现实世界并不是“OO”,而OO中隐含的思想——我们可以通过某种分类法来对事物进行建模——在我看来非常基本上存在缺陷(我可以坐在桌子上、树桩上、汽车引擎盖上、别人的膝盖上,但没有一个是椅子)。即使我们转向更抽象的领域,OO建模通常也很困难、反直觉且最终没有帮助(考虑圆/椭圆或正方形/矩形的经典例子)。
那么,我错过了什么?OOP的价值在哪里,为什么所有时间和金钱都未能使软件变得更好?

11
您的比喻对于您想要的“使用案例”来说抽象得太高了;桌子、树桩、引擎盖、某人的膝盖都是由分子、原子、质子、中子、电子组成,形成足够大的表面积,使您坐在上面感受到重力的作用。 - icelava
38
无论这个相同的主题被开始多少次,它总是引起很多兴趣(尽管通常不容忍重复)。当然,被选中的答案总是赞同提问者最初意见的答案。 - TM.
4
面向对象编程(OOP)的问题在于没有把它放在正确的背景下。它非常适用于某些目的,但并不适用于所有目的。它是一个很好的工具,但不应被奉为信条。 - Mike Dunlavey
16
抱歉,我有一种感觉,你可能从未使用过任何编程语言。以下是原因:面向对象编程(OOP)是所有现代环境中基础组件库的操作基础(例如Java、.NET、Python、Ruby等)。这些基础库每天都被重复使用,如果这不算的话,我不知道还有什么算。所以请别误解我的意思,代码重用是事实,而且非常普遍!我并不想让这听起来有任何冒犯之处——只是在强调一个观点。 - Matthias Hryniszak
2
@George Jempty:在“微软如何输掉了API战争”(http://www.joelonsoftware.com/articles/APIWar.html)一文中,作者是Joel Spolsky,该段落的标题为“自动变速器赢得了胜利”。 - GodsBoss
显示剩余6条评论
45个回答

119

真实世界并不是“面向对象”的,而OO中隐含的思想——我们可以使用某些类别体系来模拟事物,似乎在我看来有很根本性的缺陷。

虽然这是正确的,并且其他人也已经注意到了这一点(比如STL发明者Stepanov),但其余部分都是无稽之谈。OOP可能存在缺陷,当然它肯定不是万能药,但它使得大型应用程序变得更简单,因为它是减少依赖关系的好方法。当然,这仅对“良好的”OOP设计成立,粗糙的设计不会给任何优势。但是,良好的、解耦的设计可以很好地使用OOP进行建模,而使用其他技术则不行。

还有更好、更通用的模型(比如Haskell的类型模型),但这些模型通常更复杂和/或难以高效实现。OOP是一种极端之间的很好的折衷方案。


10
有意思的是,这个回答获得的赞数比问题和已批准的答案的总和还多。 - Brad Gilbert
15
我认为 Haskell 的类型系统比面向对象的更加直观。 - axblount
4
@Konrad说:"但它使得大规模应用程序更加简单" - 嗯,我不确定这是正确的。它使得应用程序更易于维护,即更改一个部分不应该影响到其他部分,但更简单?这个有点难以接受... - Mitch Wheat
2
@BradGilbert:当然,提问者选择了一个与他最初问题中的观点完全一致的答案。这就引出了一个问题,如果你已经决定了自己的答案,为什么还要问这个问题呢? - TM.
2
@Mitch:我会毫不犹豫地声称,如果没有某种形式的面向对象编程,你今天是无法编写大型应用程序的。这里所说的大型应用程序指的是代码行数大于100万行。 - Konrad Rudolph
显示剩余5条评论

45

面向对象编程不是关于创建可重用的类,而是关于创建可用的类。


1
还好。但这并不能解决“重复造轮子”的问题,这在软件开发中实际上是一个严重的问题 - 我们不是有一个库,有N个人寻找缺陷,而是有N个库,每个库只有一对眼睛在寻找缺陷。在你需要开始重用它们之前,你可以构建很多可用的类。就我所知,面向对象编程在代码重用方面存在根本性的缺陷 - 它隐藏了数据并将其“嫁接”到方法上,从而使得该数据无法访问或者难以互操作。 - Armen Michaeli

42
过于频繁地,类被用作其语法糖; 它将记录类型的函数放入它们自己的小命名空间中。
是的,我也发现这种情况过于普遍了。这不是面向对象编程(OOP)。这是基于对象编程(OBP)和以数据为中心的编程。在我使用OO语言的10年中,我看到大多数人都在做OBP。在我看来,OBP很快就会崩溃,因为你实际上得到了最糟糕的两个方面:1)没有遵循经过验证的结构化编程方法的过程化编程;2)没有遵循经过验证的OOP方法的OOP。
正确地使用OOP是一件美妙的事情。它使非常困难的问题变得容易解决,并且对于未经培训的人(并不是要显摆),它几乎可以像魔术一样神奇。话虽如此,OOP只是编程方法论工具箱中的一个工具。它不是万能的方法论。它只是适合大型业务应用程序。
大多数使用OOP语言的开发人员在日常使用的框架和类型示例中利用了OOP的优点,但他们只是不知道而已。以下是一些非常简单的示例:ADO.NET、Hibernate/NHibernate、日志框架、各种语言集合类型、ASP.NET堆栈、JSP堆栈等... 这些都是在代码库中广泛依赖OOP的东西。

32

重用不应该成为面向对象编程(OOP)或任何其他范式的目标。

重用是良好设计和适当抽象水平的副作用。代码通过做一些有用的事情来实现重用,但不要做太多以至于让它变得不灵活。无论代码是面向对象还是其他方式,我们都会重用可行且不容易自己完成的东西,这就是实用主义。

把面向对象视为通过继承实现重用的新方法是根本上错误的想法。正如您所指出的那样,违反LSP规则屡见不鲜。相反,面向对象应该正确地被视为管理问题领域复杂性的方法。目标是系统随时间的可维护性。实现这个目标的主要工具是将公共接口与私有实现分离。这使我们能够强制执行像“只能使用...修改”这样的规则,而不是通过代码审查。

使用这种方式,我相信你会同意,我们可以创建和维护非常复杂的系统。这有很多价值,而在其他范式中实现它并不容易。


3
关于重用和面向对象是不同的关注点,这是正确的。 - Dan Rosenstark

28
几乎可以说是宗教性的,但我认为你对现代面向对象编程的状态描绘过于悲观了。我会认为它实际上已经降低了成本,使大型软件项目可管理等等。这并不意味着它解决了软件混乱的根本问题,也不意味着普通开发人员都是面向对象编程专家。但将函数模块化为对象组件确实减少了世界上的混乱代码量。
我能想到数十个库,它们非常易于重用,并节省了无法计算的时间和金钱。
但就面向对象编程而言,如果浪费了时间,那么我会说这是由于缺乏程序员培训,再加上学习特定语言面向对象映射的陡峭学习曲线所致。有些人“懂”面向对象编程,而其他人则永远不会。

2
我刚刚给了你一个赞,让你的积分超过了2000分 - 希望它能保持下去。 :P - Jason Bunting
5
很少见到面向对象编程被有效地教授。 - Jon W
你的回答听起来很像是敏捷/Scrum培训师在被问及是否有意义时给出的回答 - “如果你做得对,它非常有用;如果你失败了,那么你一定是做错了”。随意使用“可重用”和“可维护”等词汇很容易,但实际上很难量化这些特性,并且也没有一个配方可以告诉你如何编写良好的OOP(尽管有成千上万本书试图这样做)。我们还养成了明显忽略硬件的坏习惯,这导致了在避免过早优化的祭坛上可怕的性能。 - Tom

24

没有实证证据表明面向对象是人们更自然地思考世界的方式。在编程心理学领域中有一些研究表明,OO并不比其他方法更适合。

面向对象的表示似乎不是普遍更可用或不可用的。

仅采用面向对象的方法并要求开发人员使用此类方法是不够的,因为这可能会对开发人员的生产力以及开发的系统质量产生负面影响。

这段话摘自于《ACM通讯》2000年10月的文章“关于OO表示的可用性”。该文章主要比较了面向对象与过程化方法。有很多关于使用OO方法的人们如何“思考”的研究(《人机交互》1995年第10卷有一个专门探讨OO研究的主题),但我所读的资料没有任何迹象表明面向对象方法比传统的过程化方法更适合。


18
它运行良好。但它不能强制劣质程序员编写优秀的代码。因此,周期性地会针对此进行抨击。 - chaos
6
面向对象编程(OOP)是工具箱中的一种工具,而不是唯一的工具,训练、经验和判断力是无法替代的。@melaos 中间给出了总结。 - Mike Dunlavey
44
当有人发表“问题”以辩论某个观点,然后接受第一个支持他观点的答案时,我感到有点有趣,尽管有更高评价的问题支持相反的观点。人性很有意思。 - Bill K
3
@melaos,这些文章的总结是没有任何证据表明面向对象编程是人们自然思考的方式,因此,并不比其他构建程序的方式更优越。 - Svend
6
@Bill K:这是为数不多的几个回答之一,提供了引用而非手舞足蹈和仅仅坚持OO“必须”更好的回答。如果所引用的文献支持OO并没有任何特别的改进或任何特别的好处的观点,并因此支持我的原始立场,我不确定为什么我应该忽略它。您能否提供类似的参考资料来反驳我的原始帖子? - DrPizza
显示剩余4条评论

21
我认为在过程式代码中也使用了不透明上下文对象(例如Win32中的HANDLE和C中的FILE*,这是两个众所周知的例子 - 实际上,HANDLE存在于内核模式屏障的另一侧,这真的不能更封装了)。我很难看出这与OOP有什么特别关系。 HANDLE(以及整个WinAPI)确实是OOP的! C不太支持OOP,因此没有特殊的语法,但这并不意味着它不使用相同的概念。 WinAPI在任何意义上都是面向对象的框架。
你看,这就是每次讨论OOP或其他技术时的麻烦所在:没有人清楚定义,每个人都在谈论其他事情,因此达不成共识。对我来说,这似乎浪费时间。

1
我正准备发布非常相似的内容。 - Brad Gilbert
我同意你可以在没有特殊语法的情况下使用面向对象编程(OOP)的概念,但另一方面,我不认为WinAPI是OOP概念的好例子。 - Lena Schimmel

14

它是一种编程范式.. 旨在使我们这些凡人更轻松地将问题分解成更小、可处理的部分。

如果你觉得没有用处.. 不要使用它,不要为培训付费,保持愉快。

而我则认为它很有用,所以我会使用它 :)


14

相对于直接的过程性编程,面向对象编程的第一个基本原则是信息隐藏和封装的概念。这个想法导致了的概念,即将接口与实现分离。这些都是非常重要的概念,是为了以一种不同且更好(我认为)的方式构建程序设计框架。你无法反驳这些属性-没有做出任何权衡,这总是一种更清晰的模块化方法。

面向对象编程的其他方面,包括继承和多态性也很重要,但是正如其他人所暗示的那样,这些概念通常被过度使用。即有时人们使用继承和/或多态性是因为他们可以使用,而不是因为他们应该使用。它们是强大的概念且非常有用,但需要明智地使用,并不是自动赢得面向对象编程的优势。

相对于重复使用。我同意重复使用在面向对象编程中被夸大了。这是定义良好的对象(通常是更原始/通用类)的可能副作用,并且是封装和信息隐藏概念的直接结果。它可能更容易被重复使用,因为定义良好的类的接口更加清晰并且有点自解释。


1
软件开发人员都渴望重复使用代码,无论他们使用面向对象编程还是函数式编程等任何范式。但这与不断变化的软件需求产生冲突,因此设计灵活的方案成为了一个问题。 - Geoglyph
将“notion of the class that separates the interface from implementation”翻译成中文:我认为接口是接口,类是实现?也许我只是一个过于流程导向的思考者,但我认为多态性是面向对象编程的关键;我认为“一堆C函数”与“一个Java类”同样能够将接口与实现分离。也许我完全错了? - Jonas Kölker
2
@Jonas - 针对你所说的“一堆C函数”---我同意它们可以将接口与实现分离,到那个时候它就开始变成OOP了。如果示例继续定义一个C结构体,API在其上运行,那么你基本上已经创建了封装(特别是如果API在结构上进行不透明操作)......然后它真正成为了C中的OOP。 - Tall Jeff

12

OOP的问题在于它被过度吹捧了。

正如Alan Kay最初构想的那样,它是一个很好的替代方案,可以避免使用原始数据和全局例程的先前实践。

然后一些管理咨询师类型的人抓住了它,并将其作为软件的救世主来销售,学术界和行业像旅鼠一样跟随其后。

现在他们正在像旅鼠一样跟随其他被过度吹捧的好主意,比如函数式编程。

那么我会做些什么不同的事情呢?很多,我写了一本关于这个问题的书(已经绝版了 - 我没有获得一分钱,但你仍然可以买到副本)。Amazon

我的建设性回答是将编程视为编码需求的方式,而非对现实世界中事物建模的方法。

这非常不同,基于信息论(任何人都能理解的层次)这一思路。它认为编程可以看作是定义语言的过程,良好的编程技巧对于编写高质量的代码至关重要。

它推崇特定领域语言(DSLs)的概念,强烈支持DRY(不要重复自己),大力赞成代码生成,从而产生比现代应用程序典型数据结构要少得多的软件。

它试图重新激发创新的想法,以及即使被广泛接受的观点也应该受到质疑。


很好。由于这本书已经绝版了,你不会想提供PDF文件,对吧?亚马逊寄到阿根廷的速度非常慢... - Dan Rosenstark
我怀疑在流程的早期某些优秀的编码人员对面向对象编程(OOP)的潜力大加赞扬,而有人听到后误认为每个人都能和会按同样的方式做。 - chaos
@Jonas Kölker:抱歉,我不明白 - 我有点慢。顺便说一句,丹麦很酷 :-) - Mike Dunlavey
1
@Mike Dunlavey 尊敬的先生,我能否支持 @yar 的好奇心,了解是否有机会通过互联网阅读/获取您的书籍[至少部分内容]?因为您提出/开发的有效软件[组件]规范/实现方式似乎与我最近认识到的方式非常相似,我希望学习或接受教导(而不是像那些写得很好但含糊不清的主流OO书籍所介绍的“货物”方式)。提前感谢[来自俄罗斯的欢呼:)]。 - mlvljr
1
@mlvljr:好的,最快的方法可能就是扫描它并制作一个大的PDF文件。我会尽快在接下来的几天里处理它。不要让我忘记[对莫斯科最近发生的事情表示真诚的哀悼,并来自湿漉漉的马萨诸塞州的欢呼]。 - Mike Dunlavey
显示剩余3条评论

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