翻译:为什么我不使用类

331 阅读4分钟

原文:Why I Don't Use Classes

最近,我的一个小组成员指出我们的项目代码库没太多的类。这一观察无关正面负面。总的来说这只是有关团队特定代码风格的观察。

那时候我没有思考太多。但是回头看,这个观察引发了一些好的在写软件时我重视的东西的方面上的反省。我不是写这个博客说服其他人遵从我倾向遵从的模式。但是我希望这个博客能促使你有自己的反省。

补个上下文,我的项目近期是全栈 Typescript,并且我写软件所重视的深受 Typescript 生态的经验影响。我想有这里有一些在其他生态适用的横向关注点,但我不打算宣称就是那样。

我也应该指出我不是活跃地避免写类。我只是倾向于其他解决方案,通常是函数方案高于面向对象方案。由于我主要的时间花在 Typescript 生态上,我有充裕的选择某个范式解决当前手上问题的机会。

抽象

我很讨厌用类做好的抽象。我承认结果是混合的,但是通常,使用继承和多态给问题空间建模会演变成一团乱。我想我知道至少两个这种混乱的源头。

糟糕的方法名

首先,如果这些方法覆盖基类方法则类最终会有糟糕的方法名。我已经被太多的最终做的比说的多的方法名所愚弄。基类常常为方法应该 的而设置名称。但是当其他类扩展和覆盖这些方法去解决它们的问题空间时,它们通常最终拥有一些原本任务之外的其他职责。

举个例子,我实现了一些管理数据库表的类,所以它要实现一个需要 "update" 方法的抽象类。好的,某些表在更新时需要做更多而不仅是“更新”一个记录,比如向边上的表插入一条日志。尽管在开始可能是无辜的,但我已见过相当多的方法继续在它们的职责集合里膨胀。

也许只是我的组织问题。但是我发现创建不属于类的函数组成功得多。并且我能给它们我想要的任何名称以及如我所愿的将职责分割到新函数里。

类的膨胀

其次,我注意到类有变大的趋势。它们会收集需要和类的上下文共存的功能片段,通常为了访问类的内部状态。这种内部状态依赖使把方法分解成逻辑块变得困难。

这通常不会巨大的痛点,但是我所在的团队更喜欢使用模块里的将状态传给它们的函数组。如果需要,将大模块拆分成小块更容易一些。

状态管理

我不善于在类中管理状态。类中包含和控制的状态是有趣和非预期行为的原因。尽管使用类管理的状态看起来很适合一类问题,我见过一个模式、基于类的解决方法拥有自己的状态、却产生有 bug 的实现。

一个具体的这个模式的例子是基于类的 React 组件。一次又一次,不论何时我想试用一个类组件,那个组件终会成为 bug 源头、如果它试图管理某个内部状态。

我想过可能状态管理就是天生复杂的,也许并不应该责备类。然而,现在对于函数组件我用 React hooks 来管理状态,在我的 UI 代码中我没有遇到这类 bug。在我的项目中,看起来像是移除类的构造和用能在组件间传递的函数代替它简化了状态管理。

类的替代品

如我上面提到的,我喜欢用暴露函数组的模块。这些函数接收状态和其他依赖。这些模块更像我的同事 Drew 描述的 函数模块模式

也许在 Typescript 生态中函数比类更自然。如果我多做一些 .NET 开发,我可能会欣赏类多一点。如果我尝试用面向对象范式而不是函数范式,也许我会获益。截至近期,我只是没发现一个信服的理由在我的项目里那样做。