设计模式六大原则(一)单一职责原则
单一职责的定义
单一职责的定义:不要存在多于一个类变更的原因。通俗的说一个类只负责一项职责。
单一职责原则针对的问题
有一个类负责两个不同的职责:职责p1和职责p2。当因为职责p1的需求发生改变而需求修改类T的时候,有可能会导致原本运行正常的职责p2功能发生故障。
单一职责原则的解决方案
遵循单一职责原则,分别建立两个类T1、T2,使T1完成职责p1功能。这样修改类T1的时候,不会使职责P2发生故障风险。同理,当修改T2的时候,也不会使职责P1发生故障风险。
单一职责原则的认识
说到单一职责原则,很多人都会不屑一顾,因为它太简单了。稍有经验的程序员即使从来没有读过设计模式,从来没有听说过单一职责原则,在设计软件的时候也会自觉遵守这个重要原则,因为这是一个常识。在软件编程中,谁也不希望因为修改了一个功能导致其他的功能发生故障。而避免出现这一问题的方法便是遵循单一职责原则。虽然单一职责原则如此简单,并且被认为是常识,但是即使是经验丰富的程序员写出的程序也会有违背这一设计原则的代码存在。这是职责扩散导致的。所谓的职责扩散,指的就是因为某种原因,职责P1被分化为粒度更细的职责P1和P2。
比如说,类T只负责一个职责P,这样设计是符合单一职责原则的。后来由于某种原因,或许是需求变更了,又或许是程序的设计者境界提高了,需要将职责P细分为粒度更细的职责P1和P2。这时候,如果要使程序遵循单一职责原则,就需要将类T也分解为两个类T1和T2,分别去负责P1和P2两个职责。但是在程序已经写好的情况下这样做,十分浪费时间和精力。所以,简单地修改类T,用它来负责两个职责是一个比较不错的选择,虽然这样做会有悖于单一职责原则。
适当地违背单一职责原则有时候反而能提高开发效率,因此设计原则还是要按照实际需求来选择使用的。
单一职责的案例
这个类图太easy了,即使一个初级的程序员也可以看出这个接口设计的有问题,用户的属性和用户的行为没有分开,这是一个严重的错误!这个接口确实设计的一团糟,应该把用户的信息抽取成一个BO (BussIness Object,业务对象),把行为抽取成一个Biz(Bussiness Logic,业务逻辑),按照这个思路类图进行修正
重新拆封成两个接口,IUserBO负责用户的属性、IUserBiz负责用户的行为。接下来我们先来看一看分拆成两个接口怎么使用,我们现在是面向接口编程,所以产生了这个UserInfo对象之后,当然可以把他当IUserBO接口使用。也可以当IUserBiz接口使用,这要看你在什么地方使用了。要获得用户信息,就当是IUserBO实现类;要维护用户信息,就把他当作IUserBiz的实现类就成了,代码如下:
//我要赋值了,我就认为它是一个纯粹的BO IUserBO
IUserInfo userInfo = new UserInfo();
//我要执行动作了,我就认为是一个业务逻辑类
userBO = (IUserBO)userInfo;
userBO.setPassword("abc");
//我要执行动作了,我就认为是一个业务逻辑类
IUserBiz userBiz = (IUserBiz)userInfo;
userBiz.deleteUser();
确实可以如此,问题也解决了,但是我们来分析一下刚才的动作,为什么要把一个接口拆成两个呢?其实,在实际使用中,我们更倾向于使用两个不同的类或接口;一个是IUserBO,一个是IUserBiz
以上我们把一个接口拆分成两个接口的动作,就是依赖单一职责原则。
下面来看下一个例子,电话这玩意,是现代人就离不了,电话通话的时候有4个过程发生:拨号、通话、回应、挂机,那我们写一个接口。
代码如下:
public interface IPhone {
//拨通电话
public void dial(String phoneNumber);
//通话
public void chat(Object o);
//通话完毕,挂电话
public void hangup();
}
实现类比较简单就不写了,这个接口有问题吗,相信大家都觉得没有问题,是的,这个接口接近于完美,但是它只负责一件事情吗?是因为一个原因引起的变化吗?好像不是。
Iphone这个接口可不是只有一个职责,它包含了两个职责:一个协议管理,一个数据传送。dial() 和 hangup()两个方法实现的是协议管理,分别负责拨号接通和挂机;chat()实现的是数据传送,通过这样分析,我们发现类图上IPhone接口包含了两个职责,而且职责的变化不互相影响,那么就考虑拆分成两个接口
单一职责原则的优点
- 类的复杂性降低,实现什么职责都有清晰明确的定义;
- 可读性提高,复杂性降低,那当然可读性提高了;
- 可维护性提高,可读性提高,那当然可维护性提高了;
- 变更引起的风险降低,变更是必不可少的,如果对接口的单一职责做的好,一个接口修改只对相应的实现类有影响,对其他接口无影响,这对系统的扩展性、维护性都有非常大的帮助。
注意: 单一职责原则提出了一个编写的标准,用职责和变化原因来衡量接口或设计的是否优良,但是职责和变化原因都是不可度量的,因项目而异,因环境而异。
的