接口隔离中的单个 API

接口隔离中的单个 API

我们把接口理解为单个接口或函数(以下为了方便讲解,我都简称为 “函数”)。那接口隔离原则就可以理解为:函数的设计要功能单一,不要将多个不同的功能逻辑在一个函数中实现。

接下来,我们还是通过一个例子来解释一下。

public class Statistics {

  private Long max;

  private Long min;

  private Long average;

  private Long sum;

  private Long percentile99;

  private Long percentile999;

  //... 省略 constructor/getter/setter 等方法...

}

public Statistics count(Collection<Long> dataSet) {

  Statistics statistics = new Statistics();

  //... 省略计算逻辑...

  return statistics;

}

在上面的代码中,count () 函数的功能不够单一,包含很多不同的统计功能,比如,求最大值、最小值、平均值等等。按照接口隔离原则,我们应该把 count () 函数拆成几个更小粒度的函数,每个函数负责一个独立的统计功能。拆分之后的代码如下所示:

public Long max(Collection<Long> dataSet) { //... }

public Long min(Collection<Long> dataSet) { //... }

public Long average(Colletion<Long> dataSet) { //... }

不过,你可能会说,count () 函数也不能算是职责不够单一,毕竟它做的事情只跟统计相关。我们在讲单一职责原则的时候,也提到过类似的问题。实际上,判定功能是否单一,除了很强的主观性,还需要结合具体的场景。

  1. 如果在项目中,对每个统计需求,Statistics 定义的那几个统计信息都有涉及,那 count () 函数的设计就是合理的。

  2. 相反,如果每个统计需求只涉及 Statistics 罗列的统计信息中一部分,比如,有的只需要用到 maxminaverage 这三类统计信息,有的只需要用到 averagesum。而 count () 函数每次都会把所有的统计信息计算一遍,就会做很多无用功,势必影响代码的性能,特别是在需要统计的数据量很大的时候。

  3. 所以,在这个应用场景下,count () 函数的设计就有点不合理了,我们应该按照第二种设计思路,将其拆分成粒度更细的多个统计函数。

不过,你应该已经发现,接口隔离原则跟单一职责原则有点类似,不过稍微还是有点区别。

  1. 单一职责原则针对的是模块、类、接口的设计。

  2. 而接口隔离原则相对于单一职责原则,一方面它更侧重于接口的设计,另一方面它的思考的角度不同。它提供了一种判断接口是否职责单一的标准:通过调用者如何使用接口来间接地判定。如果调用者只使用部分接口或接口的部分功能,那接口的设计就不够职责单一。

回顾

  1. 如何理解 “接口隔离原则”?

    理解 “接口隔离原则” 的重点是理解其中的 “接口” 二字。这里有三种不同的理解。

  • 如果把 “接口” 理解为一组接口集合,可以是某个微服务的接口,也可以是某个类库的接口等。如果部分接口只被部分调用者使用,我们就需要将这部分接口隔离出来,单独给这部分调用者使用,而不强迫其他调用者也依赖这部分不会被用到的接口。
  • 如果把 “接口” 理解为单个 API 接口或函数,部分调用者只需要函数中的部分功能,那我们就需要把函数拆分成粒度更细的多个函数,让调用者只依赖它需要的那个细粒度函数。
  • 如果把 “接口” 理解为 OOP 中的接口,也可以理解为面向对象编程语言中的接口语法。那接口的设计要尽量单一,不要让接口的实现类和调用者,依赖不需要的接口函数。
  1. 接口隔离原则与单一职责原则的区别
  • 单一职责原则针对的是模块、类、接口的设计。接口隔离原则相对于单一职责原则,一方面更侧重于接口的设计,另一方面它的思考角度也是不同的。接口隔离原则提供了一种判断接口的职责是否单一的标准:通过调用者如何使用接口来间接地判定。如果调用者只使用部分接口或接口的部分功能,那接口的设计就不够职责单一。

发表评论

您的电子邮箱地址不会被公开。 必填项已用*标注

关注我们