单一职责原则(Single Responsibility Principle,SRP)(中)

简介: 单一职责原则(Single Responsibility Principle,SRP)(中)

2.3 用户管理

用户、机构、角色管理这些模块,基本上使用的都是RBAC模型(Role-Based Access Control,基于角色的访问控制,通过分配和取消角色来完成用户权限的授予和取消,使动作主体(用户)与资源的行为(权限)分离),这确实是一个很好的解决办法。

对于用户管理、修改用户的信息、增加机构(一个人属于多个机构)、增加角色等,用户有这么多的信息和行为要维护,我们就把这些写到一个接口中,都是用户管理类:

  • 用户信息维护类图
  • 1.png
  • 很有问题,用户属性和用户行为严重耦合!这个接口确实设计得一团糟:
  • 应该把用户信息抽取成一个BO(Business Object,业务对象)
  • 把行为抽取成一个Biz(Business Logic,业务逻辑)
  • 职责划分后的类图
  • 2.png
  • 重新拆分成两个接口:


IUserBO

负责用户的属性,职责就是收集和反馈用户的属性信息

IUserBiz

负责用户的行为,完成用户信息的维护和变更

我们是面向接口编程,所以产生了这个UserInfo对象后,当然可以把它当IUserBO接口使用,也可以当IUserBiz接口使用,这看你的使用场景。


要获得用户信息,就当做IUserBO的实现类

要是希望维护用户的信息,就把它当做IUserBiz的实现类

IUserInfo userInfo = new UserInfo();
// 我要赋值了,我就认为它是一个纯粹的BO
IUserBO userBO = (IUserBO)userInfo;
userBO.setPassword("abc");
// 我要执行动作了,我就认为是一个业务逻辑类
IUserBiz userBiz = (IUserBiz)userInfo;
userBiz.deleteUser();

确实这样拆分后,问题就解决了,分析一下我们的做法,为什么要把一个接口拆分成两个?

实际的使用中,更倾向于使用两个不同的类或接口:一个是IUserBO,一个是IUserBiz

  • 项目中经常采用的SRP类图
  • image.png
  • 以上我们把一个接口拆分成两个接口的动作,就是依赖了单一职责原则,那什么是单一职责原则呢?单一职责原则的定义是:应该有且仅有一个原因引起类的变更。

2.4 电话通话

电话通话的时候有4个过程发生:拨号、通话、回应、挂机。

那我们写一个接口

image.png

电话过程

image.png

这个接口有问题吗?是的,这个接口接近于完美。

单一职责原则要求一个接口或类只有一个原因引起变化,即一个接口或类只有一个职责,它就负责一件事情,看看上面的接口:


只负责一件事情吗?

是只有一个原因引起变化吗?

好像不是!IPhone这个接口可不是只有一个职责,它包含了两个职责:


协议管理

dial()和hangup()两个方法实现的是协议管理,分别负责拨号接通和挂机

数据传送

chat()实现的是数据的传送,把我们说的话转换成模拟信号或数字信号传递到对方,然后再把对方传递过来的信号还原成我们听得懂的语言。

协议管理的变化会引起这个接口或实现类的变化吗?

会的!

那数据传送(电话不仅可以通话,还可以上网!)的变化会引起这个接口或实现类的变化吗?

会的!


这里有两个原因都引起了类变化。这两个职责会相互影响吗?


电话拨号,我只要能接通就成,不管是电信的还是联通的协议

电话连接后还关心传递的是什么数据吗?

经过分析,我们发现类图上的IPhone接口包含了两个职责,而且这两个职责的变化不相互影响,那就考虑拆分成两个接口:


职责分明的电话类图

image.png

完全满足了单一职责原则要求,每个接口职责分明,结构清晰,但相信你在设计时肯定不会采用这种方式。一个 Phone类要把ConnectionManager和DataTransfer组合在一块才能使用。组合是一种强耦合关系,共同生命周期,这样强耦合不如使用接口实现,而且还增加了类的复杂性,多了俩类。

那就再修改一下类图:


简洁清晰、职责分明的电话类图

image.png

一个类实现了两个接口,把两个职责融合在一个类中。

你可能会说Phone有两个原因引起变化了呀!

是的,但是别忘了我们是面向接口编程,我们对外公布的是接口而非实现类。而且,若真要实现类的单一职责,还就必须使用组合模式了,这会引起类间耦合过重、类的数量增加等问题,人为地增加了设计复杂性。


好处

  • 类的复杂性降低,实现什么职责都有清晰明确的定义
  • 可读性提高,复杂性降低,那当然可读性提高了
  • 可维护性提高,可读性提高,那当然更容易维护了
  • 变更引起的风险降低,变更是必不可少的。若接口的单一职责做得好,一个接口修改只对相应的实现类有影响,对其他的接口无影响。这对系统的扩展性、维护性都有非常大帮助。

单一职责原则最难划分的就是职责。

一个职责一个接口,但问题是“职责”没有一个量化的标准,一个类到底要负责那些职责?这些职责该怎么细化?细化后是否都要有一个接口或类?

这些都需要从实际的项目去考虑,从功能上来说,定义一个IPhone接口也没有错,实现了电话的功能,而且设计还很简单,仅仅一个接口一个实现类,实际的项目我想大家都会这么设计。项目要考虑可变因素和不可变因素,以及相关的收益成本比率,因此设计一个IPhone接口也可能是没有错的。


但若纯从“学究”理论上分析就有问题了,有两个可以变化的原因放到了一个接口中,这就为以后的变化带来了风险。如果以后模拟电话升级到数字电话,我们提供的接口IPhone是不是要修改了?接口修改对其他的Invoker类是不是有很大影响?


单一职责原则提出了一个编写程序的标准,用“职责”或“变化原因”来衡量接口或类设计得是否优良,但是“职责”和“变化原因”都是不可度量的,因项目而异,因环境而异。


目录
相关文章
|
11月前
|
数据库连接 数据库
深入理解单一职责原则(Single Responsibility principle )
深入理解单一职责原则(Single Responsibility principle )
110 0
|
11月前
|
存储 数据库 数据格式
深入理解依赖倒置原则(Dependence Inversion Principle)
深入理解依赖倒置原则(Dependence Inversion Principle)
115 0
|
8月前
六大设计原则-单一职责原则【Single Responsibility Principle】
六大设计原则-单一职责原则【Single Responsibility Principle】
31 0
|
8月前
六大设计原则-接口隔离原则【Interface Segregation Principle】
六大设计原则-接口隔离原则【Interface Segregation Principle】
29 0
|
11月前
|
XML Java BI
深入理解接口隔离原则(Interface Segregation Principle)
深入理解接口隔离原则(Interface Segregation Principle)
151 0
|
程序员 数据库管理
设计原则(二):SRP 单一职责原则
设计原则(二):SRP 单一职责原则
126 0
|
存储 设计模式 Dubbo
行为型-Chain Of Responsibility
职责链模式的原理和实现 职责链模式的英文翻译是 Chain Of Responsibility Design Pattern。在 GoF 的《设计模式》中,它是这么定义的: Avoid coupling the sender of a request to its receiver by giving more than one object a chance to handle the request. Chain the receiving objects and pass the request along the chain until an object handles it.
104 0
行为型-Chain Of Responsibility
|
程序员
单一职责原则(Single Responsibility Principle,SRP)(上)
单一职责原则(Single Responsibility Principle,SRP)
124 0
单一职责原则(Single Responsibility Principle,SRP)(上)
|
设计模式 项目管理 数据库
单一职责原则(Single Responsibility Principle,SRP)(下)
单一职责原则(Single Responsibility Principle,SRP)(下)
409 0
单一职责原则(Single Responsibility Principle,SRP)(下)
|
测试技术
【愚公系列】2021年12月 面向对象设计原则(一)-单一职责原则(Single Responsibility Principle or SRP)
【愚公系列】2021年12月 面向对象设计原则(一)-单一职责原则(Single Responsibility Principle or SRP)
133 0