设计模式六大原则之【单一职则原则】
一、什么是单一职责原则首先, 我们来看单一职责的定义.
单一职责原则,全称Single Responsibility Principle, 简称SRP.
A class should have only one reason to change
类发生更改的原因应该只有一个
就一个类而言,应该仅有一个引起它变化的原因。应该只有一个职责。如果一个类有一个以上的职责,这些职责就耦合在了一起。一个职责的变化可能会削弱或者抑制这个类完成其他职责的能力。这会导致脆弱的设计。当一个职责发生变化时,可能会影响其它的职责。另外,多个职责耦合在一起,会影响复用性。想要避免这种现象的发生,就要尽可能的遵守单一职责原则。
单一职责原则的核心就是解耦和增强内聚性。
二、为什么要遵守单一职责原则?通常 , 我们做事情都要知道为什么要这么做, 才回去做. 做的也有底气, 那么为什么我们要使用单一职责原则呢?
1、提高类的可维护性和可读写性
一个类的职责少了,复杂度降低了,代码就少了,可读性也就好了,可维护性自然就高了。
2、提高系统的可维护性
系统是由类组成的,每个类的可维护性高,相对来讲整个系统的可维护性就高。当然,前提是系统的架构没有问题。
3、降低变更的风险
一个类的职责越多,变更的可能性就越大,变更带来的风险也就越大
如果在一个类中可能会有多个发生变化的东西,这样的设计会带来风险, 我们尽量保证只有一个可以变化,其他变化的就放在其他类中,这样的好处就是 ** 提高内聚,降低耦合 **。
三. 单一职责原则应用的范围单一职责原则适用的范围有接口、方法、类。按大家的说法,接口和方法必须保证单一职责,类就不必保证,只要符合业务就行。
3.1 【方法层面】单一职责原则的应用现在有一个场景, 需要修改用户的用户名和密码. 就针对这个功能我们可以有多种实现.
第一种:
第二种方法:
public interface UserOperate { void updateUserName(UserInfo userInfo); void updateUserPassword(UserInfo userInfo); } public class UserOperateImpl implements UserOperate { @Override public void updateUserName(UserInfo userInfo) { // 修改用户名逻辑 } @Override public void updateUserPassword(UserInfo userInfo) { // 修改密码逻辑 } }来看看这两种实现的区别:
第一种实现是根据操作类型进行区分, 不同类型执行不同的逻辑. 把修改用户名和修改密码这两件事耦合在一起了. 如果客户端在操作的时候传错了类型, 那么就会发生错误.
第二种实现是我们推荐的实现方式. 修改用户名和修改密码逻辑分开. 各自执行各自的职责, 互不干扰. 功能清晰明了.
由此可见, 第二种设计是符合单一职责原则的. 这是在方法层面实现单一职责原则.
3.2 【接口层面】单一职责原则的应用我们假设一个场景, 大家一起做家务, 张三扫地, 李四买菜. 李四买完菜回来还得做饭. 这个逻辑怎么实现呢?
方式一 /** * 做家务 */ public interface HouseWork { // 扫地 void sweepFloor(); // 购物 void shopping(); } public class Zhangsan implements HouseWork{ @Override public void sweepFloor() { // 扫地 } @Override public void shopping() { } } public class Lisi implements HouseWork{ @Override public void sweepFloor() { } @Override public void shopping() { // 购物 } }首先定义了一个做家务的接口, 定义两个方法扫地和买菜. 张三扫地, 就实现扫地接口. 李四买菜, 就实现买菜接口. 然后李四买完菜回来还要做饭, 于是就要在接口类中增加一个方法cooking. 张三和李四都重写这个方法, 但只有李四有具体实现.
这样设计本身就是不合理的.
首先: 张三只扫地, 但是他需要重写买菜方法, 李四不需要扫地, 但是李四也要重写扫地方法.
第二: 这也不符合开闭原则. 增加一种类型做饭, 要修改3个类. 这样当逻辑很复杂的时候, 很容易引起意外错误.
上面这种设计不符合单一职责原则, 修改一个地方, 影响了其他不需要修改的地方.
方法二 /** * 做家务 */ public interface Hoursework { } public interface Shopping extends Hoursework{ // 购物 void shopping(); } public interface SweepFloor extends Hoursework{ // 扫地 void sweepFlooring(); } public class Zhangsan implements SweepFloor{ @Override public void sweepFlooring() { // 张三扫地 } } public class Lisi implements Shopping{ @Override public void shopping() { // 李四购物 } }