Traits and Mixins Are Not OOP

The following text is a partial translation of the original English article, performed by ChatGPT (gpt-3.5-turbo) and this Jekyll plugin:

首先,让我直截了当地说,我们将要讨论的特性是纯粹的“毒药”,是那些迫切需要进行脑叶切除手术的人为面向对象编程带来的,就像大卫·韦斯特在他的《对象思维》一书中所建议的那样。这些特性有不同的名称,但最常见的是特征(traits)和混入(mixins)。我真的无法理解,当它具备了这些特性时,我们如何还能称之为面向对象编程。

首先,让我们简要介绍一下它们的工作原理。我们以Ruby模块作为示例实现。假设我们有一个名为Book的类:

现在,我们希望类Book使用一个有用的静态方法(一个过程)。我们可以在一个实用类中定义它,并让Book调用它:

或者我们可以使其变得更加”方便”,并且通过扩展我们的模块来直接访问其方法。

似乎很好——如果你不了解面向对象编程和静态方法之间的区别的话。而且,如果我们暂时忘记面向对象编程的纯粹性,我觉得这种方法实际上看起来不太易读,尽管它的字符数更少;当它被调用为#{caps(@title)}而不是#{TextUtils.caps(@title)}时,很难理解caps()方法是从哪里来的。你不这么认为吗?

当我们使用include时,mixin开始更好地发挥作用。我们可以组合它们来构建我们要寻找的类的行为。让我们创建两个mixin。第一个将被称为PlainMixin,将以原样打印书的标题,而第二个将被称为CapsMixin,将对已经打印的内容进行大写处理:

不使用包含的mixin调用Book将按照它的标题打印。一旦我们添加了include语句,to_s的行为将被覆盖,print方法会产生不同的结果。我们可以组合多个mixin来产生所需的功能。例如,我们可以再添加一个mixin,将标题缩写为16个字符:

我相信你已经了解它们都可以访问类Book的私有属性@title。实际上,它们对类中的一切都有完全访问权限。它们实际上是我们注入到类中的“代码片段”,使其更强大和复杂。这种方法有什么问题?

这与注解、DTO、getter和实用类的问题是一样的——它们将对象拆散并将功能片段放置在对象看不到的地方。

在混入的情况下,功能位于Ruby的模块中,它们对Book的内部结构做出了假设,并且进一步假设程序员在内部结构发生变化后仍然能理解Book的内容。这种假设完全违反了封装的概念。

混入和对象私有结构之间的紧密耦合只会导致难以维护和理解的代码。

混入的非常明显的替代方案是可组合的装饰器。请看一下文章中给出的示例。

这看起来不是和我们之前用Ruby混入(mixins)做的事情非常相似吗?

然而,与混入不同的是,装饰器让对象保持简洁且内聚,为其添加额外的功能层。相反,混入则会使对象变得更加复杂,因此更难读懂和维护。

我真诚地认为它们只是毒药。无论是谁发明它们,都离理解面向对象设计的哲学很远。

Translated by ChatGPT gpt-3.5-turbo/42 on 2023-11-17 at 16:42

sixnines availability badge   GitHub stars