设计模式之美--SOLID原则

SOLID原则是单一职责原则,开闭原则,里氏替换原则, 接口隔离原则,依赖反转原则的统称。下面,我们来详细介绍一下这5类原则。

单一职责原则(SRP)

单一职责,全称为Single Responsibility Principle。单一职责,顾名思义,就是让一个类只负责一个职责或者功能。
那么,如何判定是否职责单一呢?不同的业务场景下,对同一类的职责是否单一可能有不同的判定结果。可以从一下几个方面来判断。

  1. 类中函数或者属性过多
  2. 类中依赖其他类过多,或者依赖类的其他类过多
  3. 私有方法过多
  4. 比较难给类起一个合适的名字
  5. 类中有大量方法都是集中在类的某几个属性

开闭原则(OCP)

开闭原则的英文全称是 Open Closed Principle,即对拓展开放,对修改关闭
如何判定拓展还是修改?新增加一个功能,是在原有的代码基础上扩展代码,而非修改原有代码。
这条原则的设计初衷:只要它没有破坏原有的代码的正常运行,没有破坏原有的单元测试,我们就可以说,这是一个合格的代码改动。

基于接口或抽象实现“封闭”,基于实现接口或继承实现“开放”。

一些业务场景

场景一:函数存在多个入参的时候,需要新增的入参需求。
可以将其重构为单独类。那只需要新加属性而不用改动函数入参。
场景二:对于其分支判断,另外拆分为各个hander。对抽象类进行继承重写。

里氏替换原则

里式替换原则全称是Liskov Substitution Principle,缩写为LSP。
定义为 子类对象(object of subtype/derived class)能够替换程序(program)中父类对象(object of base/parent class)出现的任何地方,并且保证原来程序的逻辑行为(behavior)不变及正确性不被破坏。是用来指导继承关系中的子类该如何设计,保证在替换父类的时候,不该百年原有程序的逻辑以及不破坏原有程序的正确性,

违背里氏替换原则的案例

  1. 子类违背父类对输入、输出、异常的约定
  2. 子类违背父类声明要实现的功能
  3. 子类违背父类注释中所罗列的任何特殊说明

接口隔离原则

接口隔离原则全称为Interface Segregation Principle,缩写为ISP。
Robert Martin 在 SOLID 原则中是这样定义它的:“Clients should not be forced to depend upon interfaces that they do not use。”直译成中文的话就是:客户端不应该强迫依赖它不需要的接口。

如何理解接口

  1. 理解为一组接口的集合。部分接口只被部分调用者使用,将不同的接口隔离出来。例如权限隔离。
  2. 理解为单个API接口或函数,只需要使用到函数中部分功能,则可以拆分为更加细颗粒度的多个函数。
  3. 理解为OOP中的接口。就是和单一性原则类似,接口功能单一。

和单一职责的区别

单一职责是针对模块,类,接口的设计。接口隔离侧重点不同,主要是接口,并且提供了一种判断接口是否单一的标准,如果调用者只使用一部分功能,那接口的设计就不够单一。

依赖反转原则

我们先来谈一谈控制反转、依赖反转、依赖注入这三者的关系。

控制反转(IOC)

控制指的是程序对执行流程的控制,而反转是指没有使用框架钱,程序元自己控制整个程序的执行。在使用框架之后,整个程序的执行流程可以通过框架来控制。流程的控制权从程序员反转到了框架。
控制反转并不是一种具体的实现技巧,而是一个比较笼统的设计思想,一般用来指导框架层面的设计。

依赖注入(DI)

一句话概括就是:不通过new()的方式在类内部创建依赖类对象,而是将依赖的类对象在外部创建好了之后,通过构造函数、函数参数等方式传递给类使用。提高了代码的扩展性,

依赖注入框架(DI framework)

我们通过依赖注入框架的扩展点,简单配置一下所有需要的类以及类与类之间的关系,就可以实现由框架来自动创建对象、管理对象的生命周期、依赖注入等原本需要程序员来做的事情。

实际上,现成的依赖注入框架有很多,比如 Google Guice、Java Spring、Pico Container、Butterfly Container 等。不过,如果你熟悉 Java Spring 框架,你可能会说,Spring 框架自己声称是控制反转容器(Inversion Of Control Container)。

只是控制反转容器这种表述是一种非常宽泛的描述,DI 依赖注入框架的表述更具体、更有针对性。因为我们前面讲到实现控制反转的方式有很多,除了依赖注入,还有模板模式等,而 Spring 框架的控制反转主要是通过依赖注入来实现的。

依赖反转原则(DIP)

依赖反转原则也称为依赖倒置原则,英文原意为:

High-level modules shouldn’t depend on low-level modules. Both modules should depend on abstractions. In addition, abstractions shouldn’t depend on details. Details depend on abstractions.

高层模块不要依赖低层模块。高层模块和底层模块应该通过抽象来相互依赖。除此之外,抽象不要依赖具体实现细节,具体实现细节依赖抽象。

所谓的高层模块和低层模块的划分,简单的来说,在调用链上,调用者属于高层, 被调用者属于低层。

Tomcat 是运行 Java Web 应用程序的容器。我们编写的 Web 应用程序代码只需要部署在 Tomcat 容器下,便可以被 Tomcat 容器调用执行。按照之前的划分原则,Tomcat 就是高层模块,我们编写的 Web 应用程序代码就是低层模块。Tomcat 和应用程序代码之间并没有直接的依赖关系,两者都依赖同一个“抽象”,也就是 Servlet 规范。Servlet 规范不依赖具体的 Tomcat 容器和应用程序的实现细节,而 Tomcat 容器和应用程序依赖 Servlet 规范。