单一职责原则(Single Responsibility Principle)

定义:
一个类只负责一个功能领域中的相应职责,应该有且仅有一个原因引起类的变更。

实际中,一个类越复杂,可能被复用的可能性越小,变动代码也就越可能有意想不到的错误。这时候我们就需要用到单一职责原则了,这一原则可以说是最为简单的原则也是最难以实现的原则,究其原因在于代码的功能之间的关系较为繁琐细致而且在面对变化时可能原本单一的职责会划分为粒度更小的两种职责,这时候仅仅为了满足单一职责原则反而得不偿失,这时候我们必须折衷,不能一味的满足设计原则的条条框框。

针对的问题:
有一个类T负责两个不同的职责:职责P1和职责P2。当因为职责P1的需求发生改变而需要修改类T的时候,有可能会导致原本运行正常的职责P2功能发生故障。

解决方案:
遵循单一职责原则,分别建立两个类T1、T2,使T1完成职责P1功能,T2完成职责P2功能。这样,当修改类T1的时候,不会使职责P2发生故障风险。同理,当修改T2的时候,也不会使职责P1发生故障风险。

举例说明:
我们先来看一个代码中的接口的设计:

public interface IPhone {
	//拨通电话 
	public void dial(String phoneNumber);
	//通话 
	public void chat(Object o);
	//回应
	public void answer(Object o); 
	//挂断电话
 	public void huangup();
}

看上去好像没有说明问题,手机的四个功能都与手机密切相关,自然可以放在同一个ADT里,但其实这个设计还是有一定的瑕疵的,那就是它违背了单一职责原则,看起来是满足一个类只实现一个领域的相关功能(手机的打电话功能),但其实不然,我们从引起变化的角度来看,会影响这通电话成功的原因其实有两个:1)是否成功接听/挂断了对方的来电;2)双方交流是否成功。比如我们如果电话没有接通,自然不能实现功能,如果我们一方采用视频通话的形式拨打电话,而另一方却只能语音交流,那么显然这通电话的功能也没有实现,那么这两者(是否接通,交流方式是否相同)相关吗?很明显不相关,因为二者是互不影响的。
这时这个ADT接口就有了两个职责:一个是协议管理,一个是数据传送。
我们为了满足单一职责原则,最好将这两个职责分开,如图所示:
在这里插入图片描述
但我们这么做值得吗?很明显是不值得的:强耦合还增加了类的复杂性,经过折衷思考,我们期望实现下图的设计方案:
在这里插入图片描述
一个类实现了两个接口,把两个职责融合在一个类中。你会觉得这个Phone有两个原因引起变化了,是的,但是别忘记了我们是面向接口编程,我们对外公布的是接口而不是实现类。而且,如果真要实现类的单一职责,这个就必须使用组合模式了,这会引起类间耦合过重、类的数量增加等问题,人为的增加了设计的复杂性。

优点:
1、类的复杂性降低,实现什么职责都有清晰明确的定义;
2、可读性提高,复杂性降低;
3、可维护性提高;
4、变更引起的风险降低,变更是必不可少的,如果接口的单一职责做得好,一个接口修改只对相应的实现类有影响,对其他的接口无影响,这对系统的扩展性、维护性都有非常大帮助。

注意:
单一职责原则最难划分的就是职责。一个职责一个接口,但问题是“职责”是一个没有量化的标准,一个类到底要负责那些职责?这些职责该怎么细化?细化后是否都要有一个接口或类?这些都需要从实际的项目去考虑,从功能上来说,定义一个IPhone接口也没有错,实现了电话的功能,而且设计还很简单,仅仅一个接口一个实现类,实际的项目我想大家都会这么设计。项目要考虑可变因素和不可变因素,以及相关的收益成本比率,因此设计一个IPhone接口也可能是没有错的。但是,如果纯从“学究”理论上分析就有问题了,有两个可以变化的原因放到了一个接口中,这就为以后的变化带来了风险。如果以后模拟电话升级到数字电话,我们提供的接口IPhone是不是要修改了?接口修改对其他的类是不是有很大影响?!

总结:
单一职责原则提出了一个编写程序的标准,用“职责”或“变化原因”来衡量接口或类设计得是否有优良,但是“职责”和“变化原因”都是不可度量的,因项目而异,因环境而异。我们应该尽力去满足接口的单一职责,适当的满足类的单一职责,设计时向单一职责靠拢即可而不必必须满足,这也是折衷的一种体现。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值