248

这些编程范式之间有什么区别,它们是否更适合特定问题,或者是否有任何用例偏爱其中一种?

架构示例赞赏!

4

7 回答 7

140

它们都有各自的优点——它们只是解决相同问题的不同方法。

在纯粹的程序风格中,数据往往与对其进行操作的函数高度解耦。

在面向对象的风格中,数据往往带有一组函数。

在函数式风格中,数据和函数倾向于彼此有更多的共同点(如在 Lisp 和 Scheme 中),同时在函数的实际使用方式方面提供更多的灵活性。算法也倾向于根据递归和组合而不是循环和迭代来定义。

当然,语言本身只会影响首选哪种风格。即使是在像 Haskell 这样的纯函数式语言中,你也可以用过程式的风格来编写(尽管这是非常不鼓励的),甚至在像 C 这样的过程式语言中,你也可以用面向对象的风格来编程(比如在 GTK+ 和EFL API)。

需要明确的是,每种范式的“优势”仅仅是对算法和数据结构的建模。例如,如果您的算法涉及列表和树,那么函数式算法可能是最明智的。或者,例如,如果您的数据是高度结构化的,那么将其组合为对象(如果这是您的语言的本机范式)可能更有意义 - 或者,它可以很容易地编写为 monad 的功能抽象,即是 Haskell 或 ML 等语言的原生范例。

您选择使用哪个对您的项目和您的语言支持的抽象更有意义。

于 2009-02-16T07:18:26.277 回答
26

我认为现在可用的库、工具、示例和社区完全胜过范式。例如,ML(或其他)可能是最终的通用编程语言,但如果你不能为你正在做的事情获得任何好的库,那你就完蛋了。

例如,如果您正在制作视频游戏,那么 C++ 中有更多好的代码示例和 SDK,因此您可能会更好。对于小型 Web 应用程序,有一些很棒的 Python、PHP 和 Ruby 框架可以帮助您快速运行。由于编译时检查以及企业库和平台,Java 是大型项目的绝佳选择。

过去的情况是,不同语言的标准库非常小并且很容易复制 - C、C++、Assembler、ML、LISP 等。具有基础知识,但在标准化事物时往往会退缩像网络通信、加密、图形、数据文件格式(包括 XML),甚至像平衡树和哈希表这样的基本数据结构都被遗漏了!

Python、PHP、Ruby 和 Java 等现代语言现在带有一个更体面的标准库,并且有许多可以轻松使用的优秀第三方库,这在很大程度上要归功于它们采用命名空间来防止库相互冲突,和垃圾收集以标准化库的内存管理方案。

于 2009-02-16T06:49:42.477 回答
23

这些范式不必相互排斥。如果你看python,它支持函数和类,但同时,一切都是对象,包括函数。您可以在一段代码中混合和匹配功能/oop/程序样式。

我的意思是,在函数式语言中(至少在 Haskell 中,我研究过的唯一一个)没有语句!函数中只允许有一个表达式!!但是,函数是一等公民,您可以将它们作为参数传递,以及许多其他能力。他们可以用几行代码做强大的事情。

在像 C 这样的过程语言中,传递函数的唯一方法是使用函数指针,仅此一项并不能实现许多强大的任务。

在 python 中,函数是一等公民,但它可以包含任意数量的语句。所以你可以有一个包含过程代码的函数,但你可以像函数式语言一样传递它。

OOP 也是如此。像 Java 这样的语言不允许您在类之外编写过程/函数。传递函数的唯一方法是将其包装在实现该函数的对象中,然后传递该对象。

在 Python 中,您没有此限制。

于 2009-02-17T17:30:26.203 回答
14

对于 GUI,我会说面向对象的范式非常适合。窗口是一个对象,文本框是对象,确定按钮也是一个。另一方面,像字符串处理这样的东西可以用更少的开销完成,因此使用简单的程序范例更直接。

我认为这也不是语言的问题。您可以用几乎任何流行的语言编写函数式、过程式或面向对象的语言,尽管在某些语言中可能需要付出一些额外的努力。

于 2009-02-16T10:47:43.323 回答
6

为了回答您的问题,我们需要两个要素:

  1. 了解不同架构风格/模式的特点。
  2. 了解不同编程范式的特点。

软件架构风格/模式列表显示在 Wikipeida上的软件架构文章中。您可以在网络上轻松地研究它们。

简而言之,Procedural 适用于遵循过程的模型,OOP 适用于设计,Functional 适用于高级编程。

我认为你应该尝试阅读每个范式的历史,看看人们为什么创造它,你可以很容易地理解它们。

在了解它们之后,您可以将架构样式/模式的项目链接到编程范式。

于 2009-02-16T08:40:12.100 回答
2

我认为它们通常不是“对抗”的,但你可以将它们结合起来。我也认为,很多时候,你提到的词只是流行语。很少有人真正知道“面向对象”是什么意思,即使他们是它最狂热的宣扬者。

于 2009-02-16T13:58:31.087 回答
1

我的一个朋友正在使用NVIDIA CUDA编写一个图形应用程序。应用程序非常适合 OOP 范式,并且可以将问题巧妙地分解为模块。但是,要使用 CUDA,您需要使用不支持继承的C。因此,你需要聪明。

a) 你设计了一个巧妙的系统,在一定程度上模拟继承。可以办到!

i) 你可以使用一个钩子系统,它期望父 P 的每个子 C 对函数 F 有一定的覆盖。你可以让子注册他们的覆盖,这些覆盖将在需要时被存储和调用。

ii)您可以使用结构内存对齐功能将孩子转换为父母。

这可能很简洁,但要提出面向未来的可靠解决方案并不容易。您将花费大量时间来设计系统,并且无法保证您不会在项目中途遇到问题。实现多重继承更加困难,如果不是几乎不可能的话。

b)您可以使用一致的命名策略并使用分而治之的方法来创建程序。它不会有任何继承,但因为您的函数很小、易于理解且格式一致,所以您不需要它。您需要编写的代码量增加了,很难保持专注并且不屈服于简单的解决方案(黑客)。但是,这种忍者编码方式是C编码方式。在低级自由和编写好的代码之间保持平衡。实现这一点的好方法是使用函数式语言编写原型。例如,Haskell非常适合用于原型算法。

我倾向于方法b。我使用方法 a 编写了一个可能的解决方案,老实说,使用该代码感觉非常不自然。

于 2009-02-20T12:09:54.827 回答