41

[编辑:] 早些时候,我问这个问题可能是一个框架不佳的问题,关于何时使用 OOP 与何时使用过程编程——一些回答暗示我在寻求帮助理解 OOP。相反,我经常使用 OOP,但想知道何时使用过程方法。从回复来看,我认为有一个相当强烈的共识,即 OOP 通常是一种更好的全方位方法,但如果 OOP 架构从长远来看不会提供任何重用优势,则应该使用过程语言。

然而,我作为 Java 程序员的经验却并非如此。我看到了一个庞大的 Java 程序,由 Perl 大师用我编写的代码的 1/10 重写,并且看起来和我的 OOP 完美模型一样健壮。我的架构看到了大量的重用,但更简洁的程序方法产生了一个更好的解决方案。

因此,冒着重复自己的风险,我想知道在什么情况下我应该选择程序而不是面向对象的方法。您将如何提前识别 OOP 架构可能过度使用的情况以及更简洁和高效的过程方法。

任何人都可以提出这些场景的例子吗?

有什么好方法可以提前确定一个项目可以更好地通过程序编程方法来服务?

4

23 回答 23

44

在重用方面,我喜欢Glass的 3 规则(这似乎是您感兴趣的内容)。

1) 构建可重用组件的难度是单次使用组件的 3 倍
2) 一个可重用组件应该在三个不同的应用程序中进行试验,然后才能足够通用以接受重用库

由此我认为你可以推断出这些推论

a) 如果您没有预算 3 倍于构建一次性组件所需的时间,也许您应该推迟重用。(假设难度 = 时间)
b) 如果您没有 3 个地方可以使用您正在构建的组件,那么您可能应该推迟构建可重用组件。

我仍然认为 OOP 对于构建一次性组件很有用,因为您始终可以将其重构为以后真正可重用的东西。(您也可以从 PP 重构为 OOP,但我认为 OOP 在组织和封装方面有足够的好处,可以从那里开始)

于 2009-02-09T14:14:15.747 回答
18

可重用性(或缺乏可重用性)不受任何特定编程范式的约束。根据需要使用面向对象、过程、函数或任何其他编程。组织和可重用性来自你所做的,而不是来自工具。

于 2009-02-09T14:12:19.620 回答
15

您自己给出了答案 - 大型项目只需要 OOP 来防止变得过于混乱。

在我看来,OOP 的最大优势是代码组织。这包括 DRY 和封装的原则。

于 2009-02-09T14:10:57.003 回答
15

正如我们在这些评论中看到的那样,那些虔诚地支持 OOP 的人没有任何事实来证明他们的支持是正当的。他们在大学接受培训(或洗脑),只使用和赞美 OOP 和 OOP,这就是他们如此盲目地支持它的原因。他们在 PP 中做过任何真正的工作吗?除了在团队环境中保护代码免受粗心程序员的侵害之外,OOP 并没有提供太多帮助。个人在 PP 和 OOP 工作多年,我发现 PP 简单、直接且更高效,我同意以下明智的男人和女人:

(参考:http ://en.wikipedia.org/wiki/Object-oriented_programming ):

许多著名的研究人员和程序员都批评了OOP。这是一个不完整的列表:

  • Luca Cardelli 写了一篇题为“<a href="http://lucacardelli.name/Papers/BadPropertiesOfOO.html" rel="noreferrer">Bad Engineering Properties of Object-Oriented Languages”的论文。

  • Richard Stallman 在 1995 年写道:“在 Emacs 中添加 OOP 显然不是一种改进;我在开发 Lisp Machine 窗口系统时使用了 OOP,但我不同意通常认为它是一种更好的编程方式的观点。”</p>

  • Potok 等人的一项研究。OOP 和程序方法之间的生产力没有显着差异。

  • Christopher J. Date 表示,将 OOP 与其他技术(尤其是关系技术)进行批判性比较是很困难的,因为缺乏对 OOP 的一致和严格的定义。提出了OOP的理论基础,将OOP作为一种可定制的类型系统来支持RDBMS。

  • Alexander Stepanov 建议 OOP 提供了一个数学上受限的观点,并称其“几乎与人工智能一样是骗局”(可能指的是 1980 年代的人工智能项目和营销,有时回想起来被认为过于狂热)。

  • Paul Graham 建议 OOP 的目的是充当“羊群机制”,防止平庸组织中的平庸程序员“造成太大的损害”。这是以减慢知道如何使用更强大和更紧凑技术的高效程序员为代价的。

  • 引用 Erlang 的主要发明者乔·阿姆斯特朗 (Joe Armstrong) 的话说:“面向对象语言的问题在于它们拥有所有这些隐含的环境,它们随身携带。你想要一根香蕉,但你得到的是一只拿着香蕉和整个丛林的大猩猩。”</p>

  • Richard Mansfield,COMPUTE 的作者和前编辑!杂志指出,“就像多年来无数其他的知识潮流(“相关性”、共产主义、“现代主义”等等——历史上到处都是),OOP 将与我们同在,直到最终成为现实。但考虑到 OOP 目前在大学和工作场所中的普及情况,OOP 很可能被证明是一种持久的错觉。整整一代被灌输思想的程序员继续走出学院,在他们的余生中致力于面向对象编程,除了面向对象编程之外别无他法。” 并且还引用了一句话“OOP是编写程序,通过机场安检是飞行”。

于 2010-08-19T14:58:13.890 回答
13

对于任何给定的问题,我建议使用最简洁、基于标准的方法。您使用 Perl 的同事证明,一个熟悉特定工具的优秀开发人员无论采用何种方法都可以获得出色的结果。与其将您的 Java 与 Perl 项目作为程序与 OOP 辩论的一个很好的例子进行比较,我更希望看到 Perl 与类似简洁的语言(如 Ruby)之间的对峙,碰巧也有好处面向对象的。现在这是我想看到的。我的猜测是 Ruby 会名列前茅,但我对在这里挑起语言火焰大战不感兴趣——我的观点只是你为这项工作选择了合适的工具——无论哪种方法都能以最有效和最健壮的方式完成任务可能的方式。

于 2009-02-09T22:31:35.690 回答
6

我认为 DRY 原则(不要重复自己)结合一点敏捷是一种很好的方法。从最简单的工作开始逐步构建您的程序,然后逐个添加功能,并根据需要重构您的代码。

如果您发现自己一遍又一遍地编写相同的几行代码——可能使用不同的数据——是时候考虑抽象,以帮助将变化的内容与保持不变的内容区分开来。

为每次迭代创建彻底的单元测试,以便您可以放心地进行重构。

花太多时间试图预测代码的哪些部分需要可重用是错误的。一旦系统开始扩大规模,这一点很快就会变得明显。

对于具有多个并发开发团队的大型项目,您需要有某种架构计划来指导开发,但是如果您是自己工作或在小型合作团队中工作,那么如果您坚持 DRY 原则,架构就会自然而然地出现。

这种方法的另一个优点是,无论你做什么都是基于现实世界的经验。我最喜欢的类比——你必须先玩积木,然后才能想象建筑物是如何建造的。

于 2009-02-09T14:48:13.543 回答
6

我认为当你有一个非常明确的问题时,你应该使用程序风格,规范不会改变,你想要一个运行速度非常快的程序。在这种情况下,您可以用可维护性换取性能。

当您编写游戏引擎科学模拟程序时,通常会出现这种情况。如果您的程序每秒计算的次数超过百万次,则应将其优化到边缘。

您可以使用非常有效的算法,但在优化缓存使用之前它不会足够快。缓存数据可以大大提高性能。这意味着 CPU 不需要从 RAM 中获取字节,它知道它们。为了实现这一点,您应该尝试将数据彼此靠近存储,您的可执行文件和数据大小应该最小,并尝试使用尽可能少的指针(在您负担得起的情况下使用静态全局固定大小的数组)。

如果您使用指针,您会不断地在内存中跳转,并且您的 CPU 每次都需要重新加载缓存。OOP 代码中充满了指针:每个对象都由其内存地址存储。你打电话new到处都是将对象分布在整个内存中,使得缓存优化几乎不可能(除非您有一个分配器或垃圾收集器使事物彼此靠近)。你调用回调和虚函数。编译器通常不能内联虚函数并且虚函数调用比较慢(跳转到VMT,获取虚函数的地址,调用它[这涉及到将参数和局部变量压入堆栈,执行函数)然后弹出所有内容])。当你有一个循环从 0 到 1000000 每秒运行 25 次时,这很重要。通过使用程序风格,没有虚函数,优化器可以内联那些热循环中的所有内容。

于 2010-08-02T08:10:46.710 回答
5

如果项目太小以至于它包含在一个类中并且不会使用很长时间,我会考虑使用函数。或者,如果您使用的语言不支持 OO(例如 c)。

于 2009-02-09T18:16:38.097 回答
5

“面向对象语言的问题在于,他们拥有随身携带的所有这些隐含环境。你想要一根香蕉,但你得到的是一只拿着香蕉和整个丛林的大猩猩。” ——乔·阿姆斯特朗

你想要丛林吗?

于 2010-08-19T15:06:34.363 回答
4

我认为 OOP 的适用性更多地取决于您所从事的主题领域,而不是项目的规模。在某些主题领域(CAD、仿真建模等),OOP 自然地映射到所涉及的概念。然而,还有很多其他领域的映射最终变得笨拙和不协调。许多人在所有事情上都使用 OOP 似乎花了很多时间试图将方形钉子敲入圆孔中。

OOP 有它的位置,但过程式编程、函数式编程等也有它的位置。看看你要解决的问题,然后选择一种编程范式,它允许你编写最简单的程序来解决它。

于 2009-02-09T15:32:44.793 回答
4

对于某种类型的程序,程序程序可以更简单。通常,这些是类似脚本的短程序。

于 2009-02-09T22:39:33.487 回答
3

这两个概念不是互斥的,你很可能会结合使用 PP 和 OOP,我看不出如何隔离它们。

于 2009-02-09T14:03:53.027 回答
3

考虑这种情况:您的代码不是面向对象的。您在整个程序中都有数据结构和许多对数据结构进行操作的函数。每个函数都将数据结构作为参数,并根据数据结构中的“data_type”字段执行不同的操作。

如果一切正常并且不会改变,谁在乎它是否是 OO?它正在工作。完成。如果你能在程序上更快地写作,那么也许这就是要走的路。

但是你确定它不会改变吗?假设您可能会添加新类型的数据结构。每次添加希望这些函数对其进行操作的新数据结构类型时,您必须确保找到并修改其中的每一个函数以添加新的“else if”案例来检查并添加您想要的行为影响新型数据结构。随着程序变得更大和更复杂,这种痛苦也会增加。这越有可能,使用 OO 方法的效果就越好。

而且 - 你确定它没有错误吗?更多涉及的切换逻辑会增加测试每个代码单元的复杂性。通过多态方法调用,语言为您处理切换逻辑,并且每个方法都可以更简单、更直接地进行测试。

于 2009-06-10T15:28:09.743 回答
2

我相信 Grady Booch 曾经说过,你真的开始从 10000 多行代码的 OOP 中受益匪浅。

但是,我总是采用 OO 方式。即使是200行。从长远来看,这是一种优越的方法,而开销只是一个被高估的借口。所有的大事都是从小事开始的。

于 2009-02-09T14:20:31.317 回答
2

OOP 的目标之一是使可重用性更容易,但这不是唯一的目的。学习有效使用对象的关键是设计模式。

我们都习惯了算法的概念,它告诉我们如何组合不同的过程和数据结构来执行常见的任务。相反,请查看四人组的设计模式,了解如何组合对象以执行常见任务。

在我了解设计模式之前,我几乎不知道如何有效地使用对象而不是作为超类型结构。

请记住,实现接口与继承一样重要,甚至更重要。过去,C++ 是面向对象编程的主要示例,与继承(虚拟函数等)相比,使用接口是模糊的。C++ Legacy 意味着在各种教程和广泛的概述中更加强调重用行为。从那时起,Java、C# 和其他语言已经将界面移到了更多的关注点。

接口最擅长的是精确定义两个对象如何交互。这与重用行为无关。事实证明,我们的大部分软件都是关于不同部分如何交互的。因此,与尝试制作可重用组件相比,使用界面可以带来更多的生产力提升。

请记住,像许多其他编程思想一样,对象是一种工具。您将不得不使用您的最佳判断来判断它们对您的项目的效果如何。对于我的金属切割机 CAD/CAM 软件,有一些重要的数学函数没有放在对象中,因为它们没有理由放在对象中。相反,它们从库中公开并由需要它们的对象使用。然后有一些数学函数被做成面向对象的,因为它们的结构自然会导致这种设置。(获取点列表并将其转换为几种不同类型的切割路径)。再次使用您的最佳判断。

于 2009-02-09T14:36:02.527 回答
2

您的部分答案取决于您使用的语言。我知道在 Python 中,将过程代码移动到一个类或更正式的对象中非常简单。

我的启发式方法之一是基于情况的“状态”。如果该过程污染了命名空间,或者可能影响全局状态(以一种不好的或不可预测的方式),那么将该函数封装在一个对象或类中可能是明智的。

于 2009-02-09T15:13:29.380 回答
2

我的两分钱...

过程式编程的优点

  • 简单的设计(快速的概念验证,与剧烈的动态需求作斗争)
  • 简单的项目间沟通
  • 当时间顺序很重要时很自然
  • 运行时开销更少

Procedural 代码越完善,就越接近 Functional。FP的优点是众所周知的。

于 2017-10-12T18:04:01.183 回答
1

我总是以自上而下的方式开始设计,而在顶部,用 OOP 术语来思考要容易得多。但是,当需要编写一些小的特定部分时,仅使用过程编程就可以提高效率。OOP 在设计和塑造项目方面很酷,因此可以应用分而治之的范式。但是您不能将它应用到代码的各个方面,因为它是一种宗教 :)

于 2009-02-09T14:36:39.873 回答
1

如果您在编程时“思考 OO”,那么我不确定问“我什么时候应该恢复到过程编程?”是否有意义。这相当于问java程序员他们不能做的事情,因为java需要类。(同上 .NET 语言)。

如果您必须努力克服程序上的思考,那么我建议您询问如何克服这一点(如果您愿意的话);否则留在程序上。如果进入 OOP 模式需要付出很大的努力,那么您的 OOP 代码可能无论如何都不会很好地工作(直到您沿着学习曲线走得更远。)

于 2009-02-09T18:22:52.840 回答
0

恕我直言,OOP 的长期好处超过了短期节省的时间。

就像 AZ 所说,以程序方式使用 OOP(我经常这样做)是一个很好的方法(对于较小的项目)。项目越大,您应该使用的 OOP 越多。

于 2009-02-09T15:23:33.927 回答
0

您可以在这两个概念中编写糟糕的软件。尽管如此,用面向对象语言编写、理解和维护复杂软件要比用过程语言容易得多。我用过程语言 (Oracle PL/SQL) 编写了高度复杂的 ERP 应用程序,然后切换到 OOP (C#)。它曾经是,现在仍然是一股新鲜空气。

于 2015-04-28T10:49:06.417 回答
0

到目前为止,使用 OO 进行 DRY 和封装的论点只是增加了不必要的复杂性,即它的隐含程度,以及一个类可以将许多属性和方法继承到多少层。

更不用说设计一个好的 OO 真的很难,因为你最终会添加不相关/不必要的东西,这些东西将在继承它们的整个类层中被继承。如果一个父类变得混乱,这真的很糟糕,整个代码库都是混乱的。并被重构。

还有一个事实是,这些继承的属性并不特别适合继承它的类的用例,这需要被覆盖。而对于那些根本不需要它们的人来说,只是毫无理由地拥有它们。

对于不需要共享的东西,确保有抽象属性。但是你最终不得不在所有试图继承它们的实例中实现它们。

这种继承太神奇了,而且很危险。

但我认为 OO 擅长执行应该可用的内容。但是话又说回来,太多的力量真的很容易被错误地使用。

在我看来,final 类应该是默认值。并且你需要慎重选择是否允许它继承。

于 2021-01-22T08:22:45.977 回答
-1

大多数研究发现,OO 代码比过程代码更简洁。如果您查看使用 C++ 重写现有 C 代码的项目(我不一定建议这样做,顺便说一句),您通常会看到代码大小减少了 50% 到 75%。

所以答案是——总是使用 OO!

于 2009-02-09T14:10:29.093 回答