查看“设计模式之禅 单一职责原则”的源代码
←
设计模式之禅 单一职责原则
跳到导航
跳到搜索
因为以下原因,您没有权限编辑本页:
您所请求的操作仅限于该用户组的用户使用:
用户
您可以查看和复制此页面的源代码。
===我是“牛”类,我可以担任多职吗=== :单一职责原则的英文名称是 Single Responsibility Principle,简称是 SRP。 这个设计原则备受争议,只要你想和别人争执、怄气或者是吵架,这个原则是屡试不爽的。如果你是老大,看到一个接口或类是这样或那样设计的,你就问一句:“你设计的类符合 SRP 原则吗?”保准对方立马“萎缩”掉,而且还一脸崇拜地看着你,心想:“老大确实英明”。这个原则存在争议之处在哪里呢?就是对职责的定义,什么是类的职责,以及怎么划分类的职责。我们先举个例子来说明什么是单一职责原则。 :只要做过项目,肯定要接触到用户、机构、角色管理这些模块, 基本上使用的都是 RBAC 模型(Role-Based Access Control,基于角色的访问控制,通过分配和取消角色来完成用户权限的授予和取消,使动作主体(用户)与资源的行为(权限)分离),确实是一个很好的解决办法。我们这里要讲的是用户管理、修改用户的信息、增加机构(一个人属于多个机构)、增加角色等,用户有这么多的信息和行为要维护,我们就把这些写到一个接口中,都是用户管理类嘛,我们先来看它的类图,如图所示: [[文件:用户信息维护类图.png|居中|缩略图|493x493像素]] :太 Easy 的类图了,我相信,即使是一个初级的程序员也可以看出这个接口设计得有问题,用户的属性和用户的行为没有分开,这是一个严重的错误! 这个接口确实设计得一团糟,应该把用户的信息抽取成一个 BO(Business Object,业务对象),把行为抽取成一个 Biz(Business Logic,业务逻辑),按照这个思路对类图进行修正,如图所示: [[文件:职责划分后的类图.png|居中|缩略图|815x815像素]]<blockquote>重新拆封成两个接口,IUserBO 负责用户的属性,简单地说,IUserBO 的职责就是收集和反馈用户的属性信息;IUserBiz 负责用户的行为,完成用户信息的维护和变更。</blockquote>各位可能要说了,这个与我实际工作中用到的 User 类还是有差别的呀!别着急,我们先来看一看分拆成两个接口怎么使用。OK,我们现在是面向接口编程,所以产生了这个 UserInfo 对象之后,当然可以把它当 IUserBO 接口使用。也可以当 IUserBiz 接口使用,这要看你在什么地方使用了。要获得用户信息,就当是 IUserBO 的实现类;要是希望维护用户的信息,就把它当做 IUserBiz 的实现类就成了,如代码所示:<syntaxhighlight lang="java"> …… IUserInfo userInfo = new UserInfo(); //我要赋值了,我就认为它是一个纯粹的 BO IUserBO userBO = (IUserBO) userInfo; userBO.setPassword("abc"); //我要执行动作了,我就认为是一个业务逻辑类 IUserBiz userBiz = (IUserBiz) userInfo; userBiz.deleteUser(userBO); …… </syntaxhighlight> :确实可以如此,问题也解决了,但是我们来分析一下刚才的动作,为什么要把一个接口拆分成两个呢?其实,在实际的使用中,我们更倾向于使用两个不同的类或接口:一个是 IUserBO,一个是 IUserBiz,类图如图: [[文件:项目中经常采用的 SRP 类图.png|居中|缩略图|530x530像素]] :以上我们把一个接口拆分成两个接口的动作,就是依赖了单一职责原则,那什么是单一职责原则呢?单一职责原则的定义是:应该有且仅有一个原因引起类的变更。 === 绝杀技,打破你的传统思维 === :解释到这里,估计你已经很不屑了,“切!这么简单的东西还要讲?!”好,我们来讲点复杂的。SRP 的原话解释是: :There should never be more than one reason for a class to change. :这句话初中生都能看懂,不多说,但是看懂是一码事,实施就是另外一码事了。上面讲的例子很好理解,在实际项目中大家都已经这么做了,那我们再来看看下面这个例子是否好理解。 电话这玩意,是现代人都离不了,电话通话的时候有4个过程发生:拨号、通话、回应、挂机,那我们写一个接口,其类图如图: [[文件:电话类图.png|居中|缩略图|286x286像素]] :我不是有意要冒犯 IPhone 的,同名纯属巧合,我们来看一下这个过程的代码,如代码所示:<syntaxhighlight lang="java"> /** * 电话过程 */ public interface IPhone { //拨通电话 public void dial(String phoneNumber); //通话 public void chat(Object o); //通话完毕,挂电话 public void hangup(); } </syntaxhighlight> :实现类也比较简单,我就不再写了,大家看看这个接口有没有问题?我相信大部分的读者都会说这个没有问题呀,以前我就是这么做的呀,某某书上也是这么写的呀,还有什么什么的源码也是这么写的! 是的,这个接口接近于完美,看清楚了,是“接近”!单一职责原则要求一个接口或类只有一个原因引起变化,也就是一个接口或类只有一个职责,它就负责一件事情,看看上面的接口只负责一建事情吗?是只有一个原因引起变化吗?好像不是!
返回至
设计模式之禅 单一职责原则
。
导航菜单
个人工具
登录
名字空间
页面
讨论
变种
视图
阅读
查看源代码
查看历史
更多
搜索
导航
首页
Spring Boot 2 零基础入门
Spring Cloud
Spring Boot
设计模式之禅
VUE
Vuex
Maven
算法
技能树
Wireshark
IntelliJ IDEA
ElasticSearch
VirtualBox
软考
正则表达式
程序员精讲
软件设计师精讲
初级程序员 历年真题
C
SQL
Java
FFmpeg
Redis
Kafka
MySQL
Spring
Docker
JMeter
Apache
Linux
Windows
Git
ZooKeeper
设计模式
Python
MyBatis
软件
数学
PHP
IntelliJ IDEA
CS基础知识
网络
项目
未分类
MediaWiki
镜像
问题
健身
国债
英语
烹饪
常见术语
MediaWiki帮助
工具
链入页面
相关更改
特殊页面
页面信息