单一职责原则定义是:不要存在多于一个导致类变更的原因。通俗地说,即一个类只负责一项职责。
单一职责原则针对的问题
有一个类T负责两个不同的职责:职责P1和职责P2。当因为职责P1的需求发生改变而需要修改类T的时候,有可能会导致原本运行正常的职责P2功能发生故障。
单一职责原则的解决方案
遵循单一职责原则,分别建立两个类T1、T2,使T1完成职责P1功能,T2完成职责P2功能。这样,当修改类T1的时候,不会使职责P2发生故障风险。同理,当修改T2的时候,也不会使职责P1发生故障风险。
单一职责原则的认识
说到单一职责原则,很多人都会不屑一顾,因为它太简单了。稍有经验的程序员即使从来没有读过设计模式,从来没有听说过单一职责原则,在设计软件的时候也会自觉遵守这个重要原则,因为这是一个常识。在软件编程中,谁也不希望因为修改了一个功能导致其他的功能发生故障。而避免出现这一问题的方法便是遵循单一职责原则。虽然单一职责原则如此简单,并且被认为是常识,但是即使是经验丰富的程序员写出的程序也会有违背这一设计原则的代码存在。这是职责扩散导致的。所谓的职责扩散,指的就是因为某种原因,职责P1被分化为粒度更细的职责P1和P2。
比如说,类T只负责一个职责P,这样设计是符合单一职责原则的。后来由于某种原因,或许是需求变更了,又或许是程序的设计者境界提高了,需要将职责P细分为粒度更细的职责P1和P2。这时候,如果要使程序遵循单一职责原则,就需要将类T也分解为两个类T1和T2,分别去负责P1和P2两个职责。但是在程序已经写好的情况下这样做,十分浪费时间和精力。所以,简单地修改类T,用它来负责两个职责是一个比较不错的选择,虽然这样做会有悖于单一职责原则。
适当地违背单一职责原则有时候反而能提高开发效率,因此设计原则还是要按照实际需求来选择使用的。
单一职责原则的案例
用一个类来描述程序员编写代码这个场景。
public class AnimalTest { public static void main(String[] args) { Programmer programmer = new Programmer(); programmer.program("静静"); // 静静使用IDEA编写代码。 programmer.program("标标"); // 标标使用IDEA编写代码。 } } class Programmer { void program(String programmer) { System.out.println(programmer + "使用IDEA编写代码。"); } }
在工作中发现,并不是所有的程序员都使用IDEA编写代码的,有的程序员喜欢用Eclipse,有的程序员喜欢用记事本。那么,这时候如果要遵循单一原则,就需要将Programmer类细分为野生程序员EclipseProgrammer和大佬程序员BossProgrammer。
public class AnimalTest { public static void main(String[] args) { BossProgrammer bossProgrammer = new BossProgrammer(); bossProgrammer.program("飘飘"); // 飘飘使用记事本编写代码。 EclipseProgrammer eclipseProgrammer = new EclipseProgrammer(); eclipseProgrammer.program("毛毛"); // 毛毛使用Eclipse编写代码。 } } class BossProgrammer { void program(String programmer) { System.out.println(programmer + "使用记事本编写代码。"); } } class EclipseProgrammer { void program(String programmer) { System.out.println(programmer + "使用Eclipse编写代码。"); } }
我们会发现这样修改的花销很大,因为处理要将原来的类(被调用方)分解成多个类之外,还要修改调用方的代码。这时候适当地违反单一职责原则,即在Programmer类中的program方法中使用条件分支的形式(使用程序员名硬编码)就会简单很多,只需要修改Programmer类(被调用方)即可,不需要修改调用方的代码。当然了,因为用的是硬编码,会导致很多时候条件判断失败,比如说程序员灿灿就不知道该用什么IDE去编写代码了。
上面的例子是个简单的例子(只有一个方法),实际应用中的类要比这复杂得多。一旦发生职责扩散而需要修改类的时候,除非这个类本身非常简单,否则还是遵循单一职责原则比较好。
单一职责原则的优点
1.降低类的复杂度,一个类只负责一个职责。这样写出来的代码逻辑肯定要比负责多项职责简单得多。
2.提高类的可读性,提高系统的可维护性。
3.降低变更引起的风险。变更是必然的,如果单一职责原则遵守得好,当修改一个功能的时候可以显著降低对其他功能的影响。
需要说明的一点是,单一职责原则不只是面向对象编程思想所特有的,只要是模块化的程序设计,都适用单一职责原则。比如说单一职责原则不仅仅适用于类,还适用于方法。
"做一个有温度的人。"