只有一个功能的 class 是否足够内聚?

Is a class with only one function cohesive enough?

Mark Seemann 在他的 post SOLID: the next step is Functional 中指出:

If you keep driving your design towards smaller and smaller interfaces, you'll eventually arrive at the ultimate Role Interface: an interface with a single method [...] If you apply the SRP and ISP like that, you're likely to evolve a code base with many fine-grained classes that each have a single method. That has happened to me more than once.

我担心的是这种 类 的凝聚力。这种方法是否会导致 功能凝聚力?那些 类 没有凝聚力吗? 对代码一致性有不好的影响吗?

Growing object oriented software guided by tests 书中对内聚力有一个很好的定义,其中规定如下:

An element’s cohesion is a measure of whether its responsibilities form a meaningful unit. For example, a class that parses both dates and URLs is not coherent, because they’re unrelated concepts. Think of a machine that washes both clothes and dishes—it’s unlikely to do both well. At the other extreme, a class that parses only the punctuation in a URL is unlikely to be coherent, because it doesn’t represent a whole concept. To get anything done, the programmer will have to find other parsers for protocol, host, resource, and so on. Features with “high” coherence are easier to maintain.

这可能很快进入主观领域,但我认为 SRP 和凝聚力有时是直接相关和正交的概念。如果您的 classes 只有一种方法,那么可以肯定的是,它在某种意义上是内聚的,因为它只做一件事。但是,你也失去了一些东西,即。 class 现在粒度太细,无法单独使用。

在函数式风格中,拥有这样的 classes 很有意义。这都是关于组合函数来实现结果的。 C# 使这种风格成为可能,但也非常冗长,所以我完全同意 Seemann 支持 F# 的观点,以防你以这种方式设计你的代码库。

这个设计的好坏是一个主观的问题,但我想我们可以客观地说几句。一种方法 classes 本质上几乎可以保证遵守 SRP(当然,您仍然可能会错过重点,并使用一种非常强大的方法使上帝成为 classes)。所以以这种方式编写的代码应该具有我们期望的所有好处,即。松耦合、可组合和可维护。但是,对于丢失此类代码的大局也有话要说。

我认为在大多数情况下需要两者的某种组合,在大多数代码库中倾向于使用单一方法的 classes。例如,您可以将大部分低级代码编写为可重用的库集合,具有这样的 classes。一旦接近 API 级别,您将编写此类 classes 以获得所需的逻辑,然后将此类逻辑作为更具凝聚力的功能块公开给您的客户。客户将受益于拥有更具凝聚力的高级代码路径,从而更方便地使用和更好地发现您的库支持的功能,同时还拥有以这种方式编写低级代码的所有好处可维护且可灵活更改。