设计模式之单一职责原则
定义:不要存在多于一个导致类变更的原因。通俗地说,即一个类只负责一项职责。
问题由来:类T负责两个不同的职责:职责P1,职责P2。当由于职责P1需求发生改变而需要修改类T时,有可能导致原本运行正常的职责P2功能发生故障。
解决方案:遵循单一职责原则。分别建立两个类T1、T2。这样修改时互不影响。
很多人会认为这原则太简单了,但即使是经验丰富的程序员写出的程序,也有违背这一原则的代码存在。为什么会有这一现象呢?因为有职责扩散。所谓职责扩散,就是因为某种原因,职责P被分化为粒度更细的职责P1和P2。这时负责该P职责的T类页分解为两个类T1和T2,分别负责P1、P2两个职责。但这样太浪费时间了,所以简单修改类T,用它来负责两个职责是个不错的选择,虽然这违背了单一职责原则。这样做的风险在于职责扩散的不确定性,有可能扩散为P1,P2,P3,,,Pn。所以在无法控制之前,立刻对代码进行重构。
举例说明,用一个类描述动物呼吸这个场景:
class Animal {
public void breathe(String animal){
System.out.println(animal + "呼吸空气");
}
}
public class Client {
public static void main(String[] args){
Animal animal = new Animal();
animal.breathe("牛");
animal.breathe("羊");
animal.breathe("猪");
}
}
程序上线后,发现了问题,并不是所以的动物都是呼吸空气的,比如鱼就是吸水的。修改时如果遵循单一职责原则,需要将Animal类细分为陆生动物类Terrestrial,水生动物Aquatic:
class Terrestrial{
public void breathe(String animal){
System.out.println(animal + "呼吸空气");
}
}
class Aquatic{
public void breathe(String animal){
System.out.println(animal + "呼吸水");
}
}
public class Client {
public static void main(String[] args){
Terrestrial animal = new Terrestrial();
animal.breathe("牛");
animal.breathe("羊");
animal.breathe("猪");
Aquatic animal2 = new Aquatic();
animal2.breathe("鱼");
}
}
我们发现这样修改花销是很大的,除了将原来的类分解之外,还需要修改客户端。而直接修改类Animal来达成目的虽然违背了单一职责原则,但花销却小很多。
class Animal {
public void breathe(String animal) {
if("鱼".equals(animal)){
System.out.println(animal + "呼吸水");
}else {
System.out.println(animal + "呼吸空气");
}
}
}
可以看到这种修改方式要简单很多,但存在隐患:有一天需要将鱼分为呼吸淡水的鱼和呼吸海水的鱼,则又需要修改Animal类的breathe方法,给原有功能带来风险,隐患很大。
还有一种修改方法:
class Animal {
public void breathe(String animal){
System.out.println(animal + "呼吸空气");
}
public void breathe2(String animal){
System.out.println(animal + "呼吸水");
}
}
可以看到这种方法没有改变原来的方法,这样虽然违背了单一职责原则,但在方法级别上却是符合单一职责原则的。这三种方法各有优缺点,那到底选哪种呢?我的原则:只有逻辑足够简单,才可以在代码级别上违反单一职责原则;只有类中的方法数量足够少,才可以在方法级别上违背单一职责原则。
遵循单一职责原则优点:
可以降低类的复杂度,一个类只负责一项职责,其逻辑肯定比负责多项职责的简单的多;
提高类的可读性,提高系统的可维护性;
降低变更引起的风险。
(本文内容来自“java利器”app)
下一篇: html基础用法(上)