《设计模式之禅》之六大设计原则中篇

本文主要讲依赖倒置原则和接口隔离原则。

一、依赖倒置原则

1.定义

  • 高层模块不应该依赖低层模块,两者都应该依赖其抽象;
  • 抽象不应该依赖细节;
  • 细节应该依赖于抽象;

高层模块和低层模块容易理解,每一个逻辑的实现都是由原子逻辑组成的,不可分割的原子逻辑就是低层模块,原子逻辑的再组装就是高层模块。

那什么是抽象?什么又是细节呢?
在Java语言中,抽象就是指接口或抽象类,两者都不能直接被实例化;细节就是实现类,实现接口或者继承抽象类而产生的类就是细节,其特点是可以直接被实例化,也就是可以加上一个关键字new产生一个对象。

在Java语言中的表现就是:

  • 模块间的依赖通过抽象发生,实现类之间不发生直接的依赖关系,其依赖关系是通过接口或抽象产生的;
  • 接口或抽象类不依赖于实现类;
  • 实现类依赖接口或抽象类;

采用依赖倒置原则可以减少类间的耦合性,提高系统的稳定性,降低并行开发引起的风险,提高代码的可读性和可维护性。

注意:设计是否具备稳定性,只要适当地”松松土”,观察”设计的蓝图”是否还可以茁壮地成长就可以得出结论,稳定性较高的设计,在周围环境频繁变化的时候,依然可以做到”我自岿然不动”。

2.依赖的三种写法

(1)构造函数传递依赖对象

在类中通过构造函数声明依赖对象,按照依赖注入的说法,这种方式叫做构造函数注入。

(2)Setter方法传递依赖对象

在抽象中设置etter方法声明依赖关系,依照依赖注入的说法,这是Setter依赖注入。

(3)接口声明依赖对象

在接口的方法中声明依赖对象。

3.最佳实践

依赖倒置原则的本质就是通过抽象(接口或抽象类)使各个类或模块的实现彼此独立,不互相影响,实现模块间的松耦合,我们怎么在项目中使用这个规则呢?
只要遵循如下几个规则即可:

  • 每个类尽量都有接口或抽象类或者抽象类和接口两者都具备(这是依赖倒置的基本要求,接口和抽象类都是属于抽象的,有了抽象才可能依赖倒置);
  • 变量的表面类型尽量是接口或是抽象类;
  • 任何类都不应该从具体类派生;
  • 尽量不要覆写基类的方法(如果基类是一个抽象类,而且这个方法已经实现了,子类尽量不要覆写。类间依赖的是抽象,覆写了抽象方法,对依赖的稳定性会产生一定的影响);
  • 结合里氏替换原则使用;

二、接口隔离原则

1.定义

先明确主角-接口,接口分为两种:

  • 实例接口,在Java中声明一个类,然后用new关键字产生一个实例,它是对一个类型的事物的描述,这是一种接口。比如你定义Person这个类,然后使用Person zhangSan = new Person()产生了一个实例,这个实例要遵从的标准就是Person这个类,Person类就是zhangSan的接口。Java中的类也是一种接口;
  • 类接口,Java中经常使用的interface关键字定义的接口;

那什么是隔离?
两种定义如下:

  • 客户端不应该依赖它不需要的接口;
  • 类间的依赖关系应该建立在最小的接口上;

先说第一种定义:”客户端不应该依赖它不需要的接口”,那依赖什么?依赖它需要的接口,把不需要的接口剔除掉,那就需要对接口进行细化,保证其纯洁性;
再看第二种定义:”类间的依赖关系应该建立在最小的接口上”,它要求是最小的接口,也是要求接口细化,接口纯洁,与第一个定义如出一辙,只是一个事物的两种不同描述。

归纳为一句话:建立单一的接口,不要建立臃肿庞大的接口(通俗的讲:接口尽量细化,同时接口中的方法尽量少)。

有人可能会疑惑,这与单一职责原则不是相同吗?
接口隔离原则和单一职责原则的审视角度是不相同的,单一职责要求的是类和接口职责单一,注重的是职责,这是业务逻辑上的划分,二接口隔离原则要求接口的方法尽量少。

例如一个接口的职责可能包含10个方法,这10个方法都放在一个接口中,并且提供多个模块访问,在系统外通过文档约束”不使用的方法不要访问”,按照单一职责原则是允许的,因为它要求”尽量使用多个专门的接口”。专门的接口指什么?就是指提供给每个模块的都应该是单一接口,提供给几个模块就应该有几个接口,而不是建立一个庞大的臃肿的接口,容纳所有的客户端访问。

2.保证接口的纯洁性

接口隔离原则是对接口进行规范约束,其包含以下4层含义:

  • 接口要尽量小;
  • 接口要高内聚(高内聚就是提高接口、类、模块的处理能力,减少对外交互);
  • 定制服务(定制服务就是单独为一个个体提供优良的服务);
  • 接口设计是有限度的(接口的设计粒度越小,系统越灵活,这是不争的事实);

3.最佳实践

接口隔离原则是对接口的定义,同时也是对类的定义,接口和类尽量使用原子接口或原子类来组装。但是这个原子该怎么划分是设计模式中的一大难题,在实践中科院根据以下几个规则来衡量?

  • 一个接口只服务于一个子模块或业务逻辑;
  • 通过业务逻辑压缩接口中的public方法,接口时常去回顾,尽量让接口达到”满身筋骨肉”,而不是”肥嘟嘟”的一大堆方法;
  • 已经被污染了的接口,尽量去修改,若变更风险较大,则采用适配器模式进行转化处理;
  • 了解环境,拒绝盲从。每个项目或产品都有特定的环境因素,别看到大师是这样做的你就照抄。千万别,环境不同,接口拆分的标准就不同。深入了解业务逻辑,最好的设计就出自你的手中;

那么怎么才能正确地使用接口隔离原则呢?
答案是根据经验和常识决定接口的粒度大小,接口粒度太小,导致接口数据剧增,开发人员呛死在接口的海洋里;接口粒度太大,灵活性降低,无法提供定制服务给整体项目带来无法预料的风险。

怎么准确地实践接口隔离原则?
实践、经验和领域。

文章目录
  1. 1. 一、依赖倒置原则
    1. 1.1. 1.定义
      1. 1.1.1. 2.依赖的三种写法
      2. 1.1.2. (1)构造函数传递依赖对象
      3. 1.1.3. (2)Setter方法传递依赖对象
      4. 1.1.4. (3)接口声明依赖对象
    2. 1.2. 3.最佳实践
  2. 2. 二、接口隔离原则
    1. 2.1. 1.定义
    2. 2.2. 2.保证接口的纯洁性
    3. 2.3. 3.最佳实践