Single Responsibility Principle(SRP):单一设计原则
它规定一个类只有一个发生变化的原因。如果多余一个导致类变更的原因,则违反了SRP。
问题来源:
分别建立两个类T1、T2,使T1完成职责P1功能,T2完成职责P2功能。这样当修改T1时,不会使职责P2发生故障风险,同理当修改T2时,也不会使P1发生故障。
但是现实中,不管是新手,还是资深程序员,经常会违反,这不仅仅是技术的问题,还有职责扩散,就是因为某种原因,职责P被分化成粒度更细的职责P1和P2.
比如:类T只负责一个职责P,这样设计是符合单一职责原则的。后来由于业务变更,需要将P细化成粒度更细的职责P1、p2。这时如果要遵循单一职责原则,也需要将T细化成T1和T2,分别负责P1,P2两个职责。如果程序已经完成了,这样写太浪费时间。所以简单修改T,用它来负责两个职责也是可行的。虽然这样会违背单一职责原则。(这样的风险在于职责扩散的不确定性,因为我们不会想到这个职责P,未来可能会扩散为P1,P2,P3。。。,所以记住,在职责扩散到我们无法的程度之前,立即对代码进行重构)。
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 terrestrial = new Terrestrial(); terrestrial.breathe("牛"); terrestrial.breathe("羊"); terrestrial.breathe("猪"); Aquatic aquatic = new Aquatic(); aquatic.breathe("鱼"); } }
如果要遵循单一职责原则,还需要将Client也细化成两个类,这样开销太大,如果直接修改类Animal,
class Animal{ public void breathe(String animal){ if("鱼".equals(animal)){ System.out.println(animal+"呼吸水"); }else{ System.out.println(animal+"呼吸空气"); } } } public class Client{ public static void main(String[] args){ Animal animal = new Animal(); animal.breathe("牛"); animal.breathe("羊"); animal.breathe("猪"); animal.breathe("鱼"); } }
虽然不符合单一职责原则,但是这样工作量会减少很多。但是以后如果又出现淡水鱼和海水鱼,这样又得修改Animal的breathe(),而对原有代码会调用陆地动物相关功能带来风险,也许在有一天发现“牛呼吸水”,这种修改方式直接在代码级别上违背了单一职责原则,虽然修改简单,但是隐患是最大。
class Animal{ public void breathe(String animal){ System.out.println(animal+"呼吸空气"); } public void breathe2(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.breathe2("鱼"); } }
可以看出,这种修改方式没有修改原来的方法,只是在原来类中新增一个方法,这样虽然也违背了单一职责原则,但是在方法级别上却是符合单一职责原则的,因为它并没有动原来方法的代码,。这三种方式各有优缺点。实际中,遵循的原则应该是:只有逻辑足够简单,才可以在代码级别上违反单一职责原则,只有类中方法数量比较少,才可以在方法级别上违反单一职责原则。
遵循单一职责原则优点:
- 可以降低类的复杂度,一个类只负责一个职责,其逻辑肯定比负责多项职责简单多
- 提高类的可读性,提高系统的可维护性
- 变更引起的风险降低,变更是必然的,如果单一职责原则遵守的好,当修改一个功能时,可以显著降低对其他功能的影响。
单一职责原则不只是面向对象编程思想所持有的,只要是模块化的程序设计,都使用单一职责原则。
注意:单一职责原则提出了一个编写了一个编写程序的标准,用“职责”和“变化原因”来衡量接口或类设计的是否优良,但是“职责”和“变化原因”是不可度量的,因项目而异,因环境而异。
单一职责原则很难在项目中得到体现。在实际中,会考虑技术人员的地位和话语权,考虑环境,考虑工作量,考虑人员技术水平,考虑硬件等等,最终妥协的是精彩违背单一设计原则(如果生搬硬套单一原则,那么类的数据太多,维护困难),也许随着技术的深入,单一原则会越来越体现在项目中。
转载:http://blog.csdn.net/zhengzhb/article/details/7278174/
参考:《设计模式之禅》