Why OO Sucks - 为什么面向对象糟透了?

当我第一次接触到 OOP(面向对象编程) 思想的时候,我是持怀疑态度的,但我不知道是因为什么,只是感觉这是”错误“的。OOP 推出后变得非常流行(我稍后会解释为什么),现在批评 OOP 就好比在亵渎神明。OOness(面向对象性) 成为任何一种受欢迎语言必须拥有的东西。

说到这里,我想起了在巴黎举行的第 7 届 IEEE Logic 编程大会上,法国 IBM 时任老板的主旨演讲。 IBM prolog 已经添加了很多 OO 扩展,当被问及为什么他回答:

“我们的客户想要 OO prolog,所以我们制作了 OO prolog”

Why OO Sucks - 为什么面向对象糟透了

我对 OOP (面向对象编程)的主要反对意见要追溯到其中涉及的基本思想,我将概述其中的一些思想以及我对它们的反对意见。

反对 1 - 数据结构和函数不应绑定在一起

对象以不可分割的单位将函数和数据结构绑定在一起。 我认为这是一个基本错误,因为函数和数据结构属于完全不同的世界。 为什么?

函数是功能的执行,是做什么,它们有输入和输出。输入和输出是数据结构,这些数据结构被函数改变。函数是由命令式序列构建的:“先做这个再做那个…”, 要理解函数,你必须理解事情完成的顺序(在惰性 FPL 和逻辑语言中,这个限制是放松的)。

数据结构就只是数据结构,他们什么都不做。它们本质上是声明。 “理解”数据结构比“理解”函数容易得多。

函数被理解为将输入转换为输出的黑盒。如果我理解了输入和输出,那么我就理解了函数。但这并不意味着我可以编写该函数。

函数通常是通过观察它们是计算系统中的事物来“理解”的,该系统的工作是将类型 T1 的数据结构转换为类型 T2 的数据结构。

函数和数据结构是完全不同类型的事物,因此将它们锁在同一个笼子里从根本上是错误的。

反对 2 - 一切都必须是对象

想想 “time”。在面向对象语言中,“time” 必须是一个对象。但是在非 OO 语言中,“time” 只是数据类型的一个实例。例如,在 Erlang 中有很多不同种类的时间,这些可以使用类型声明清晰明确地指定,如下所示:

-deftype day() = 1..31.
-deftype month() = 1..12.
-deftype year() = int().
-deftype hour() = 1..24.
-deftype minute() = 1..60.
-deftype second() = 1..60.
-deftype abstime() = {abstime, year(), month(), day(), hour(), min(), sec()}.
-deftype hms() = {hms, hour(), min(), sec()}.
...

请注意,这些定义不属于任何特定对象。它们无处不在,表示时间的数据结构可以被系统中的任何函数操作。

没有关联的方法。

反对 3 - 在 OOPL(面向对象编程语言)中,数据类型定义是分散在各处的

在 OOPL 中,数据类型定义属于对象。所以我无法在一个地方找到所有的数据类型定义。在 Erlang 或 C 中,我可以在单个包含文件或数据字典中定义所有数据类型。在 OOPL 中我不能这么做:数据类型定义散布在各处。

让我举一个例子。假设我想定义一个无处不在的数据结构,在 OOPL 中会带来麻烦。

正如 lisp 程序员早就知道的那样,拥有少量普遍存在的数据类型和大量用于处理它们的小函数比拥有大量数据类型和少量起作用的函数要好。

无处不在的数据结构类似于链表、数组或哈希表,或者更高级的对象,如时间、日期或文件名。

在 OOPL 中,我必须选择一些基础对象,我将在其中定义普遍存在的数据结构,所有其他想要使用该数据结构的对象都必须继承该对象。 假设现在我想创建一些“时间”对象,它属于哪里以及在哪个对象中……

反对 4 - 对象有私有状态

状态是万恶之源。特别是应该避免有副作用的函数。

虽然编程语言中的状态是不可取的,但在现实世界中状态比比皆是。我对我的银行账户状态非常关心,当我从银行存款或取款时,我希望我的银行账户状态能够正确更新。

鉴于现实世界中存在状态,编程语言应该提供哪些工具来处理状态?

OOPL说: “对程序员隐藏状态”。状态只有通过访问函数才能隐藏和可见。 传统的编程语言(C、Pascal)说: 状态变量的可见性是由语言的作用域规则控制的。 纯声明式语言说: 没有状态。 系统的全局状态被带入到所有函数中并又从所有函数中带出来,诸如 monad(用于 FPL)和 DCG(逻辑语言)之类的机制用于向程序员隐藏状态, 因此他们可以好像“状态无关紧要”的进行编程,但在必要时可以完全访问系统状态。

OOPL 的 “对程序员隐藏状态” 是最糟糕的选择。他们没有暴露状态并试图找到减少状态干扰的方法,而是将其隐藏起来。

为什么 OO 很受欢迎?

这才是 OOP 背后的真正驱动力。