设计模式六大原则(1):单一职责原则

单一职责原则

定义: 不要存在多于一个导致类变更的原因。通俗的说,即一个类只负责一项职责。

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

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

单一职责原则是最简单的面向对象设计原则,它用于控制类的粒度大小。单一职责原则定义如下:


单一职责原则(Single Responsibility Principle, SRP):一个类只负责一个功能领域中的相应职责,或者可以定义为:就一个类而言,应该只有一个引起它变化的原因。

单一职责原则告诉我们:一个类不能太“累”!在软件系统中,一个类(大到模块,小到方法)承担的职责越多,它被复用的可能性就越小,而且一个类承担的职责过多,就相当于将这些职责耦合在一起,当其中一个职责变化时,可能会影响其他职责的运作,因此要将这些职责进行分离,将不同的职责封装在不同的类中,即将不同的变化原因封装在不同的类中,如果多个职责总是同时发生改变则可将它们封装在同一类中。

单一职责原则是实现高内聚、低耦合的指导方针,它是最简单但又最难运用的原则,需要设计人员发现类的不同职责并将其分离,而发现类的多重职责需要设计人员具有较强的分析设计能力和相关实践经验。

说到单一职责原则,很多人都会不屑一顾。因为它太简单了。稍有经验的程序员即使从来没有读过设计模式、从来没有听说过单一职责原则,在设计软件时也会自觉的遵守这一重要原则,因为这是常识。在软件编程中,谁也不希望因为修改了一个功能导致其他的功能发生故障。而避免出现这一问题的方法便是遵循单一职责原则。虽然单一职责原则如此简单,并且被认为是常识,但是即便是经验丰富的程序员写出的程序,也会有违背这一原则的代码存在。为什么会出现这种现象呢?因为有职责扩散。所谓职责扩散,就是因为某种原因,职责P被分化为粒度更细的职责P1和P2。

比如:类T只负责一个职责P,这样设计是符合单一职责原则的。后来由于某种原因,也许是需求变更了,也许是程序的设计者境界提高了,需要将职责P细分为粒度更细的职责P1,P2,这时如果要使程序遵循单一职责原则,需要将类T也分解为两个类T1和T2,分别负责P1、P2两个职责。但是在程序已经写好的情况下,这样做简直太费时间了。所以,简单的修改类T,用它来负责两个职责是一个比较不错的选择,虽然这样做有悖于单一职责原则。(这样做的风险在于职责扩散的不确定性,因为我们不会想到这个职责P,在未来可能会扩散为P1,P2,P3,P4……Pn。所以记住,在职责扩散到我们无法控制的程度之前,立刻对代码进行重构。)

举例说明,用一个类描述动物呼吸这个场景:

1 class Animal{
2     public void breathe(String animal){
3         System.out.println(animal+"呼吸空气");
4     }
5 }

1 public class Client{
2     public static void main(String[] args){
3         Animal animal = new Animal();
4         animal.breathe("牛");
5         animal.breathe("羊");
6         animal.breathe("猪");
7     }
8 } 

运行结果:


1

2

3

4

5


牛呼吸空气

羊呼吸空气

猪呼吸空气

程序上线后,发现问题了,并不是所有的动物都呼吸空气的,比如鱼就是呼吸水的。修改时如果遵循单一职责原则,需要将Animal类细分为陆生动物类Terrestrial,水生动物Aquatic,代码如下:

1 class Terrestrial{
2     public void breathe(String animal){
3         System.out.println(animal+"呼吸空气");
4     }
5 }

1 class Aquatic{
2     public void breathe(String animal){
3         System.out.println(animal+"呼吸水");
4     }
5 }

 1 public class Client{
 2     public static void main(String[] args){
 3         Terrestrial terrestrial = new Terrestrial();
 4         terrestrial.breathe("牛");
 5         terrestrial.breathe("羊");
 6         terrestrial.breathe("猪");
 7
 8         Aquatic aquatic = new Aquatic();
 9         aquatic.breathe("鱼");
10     }
11 }

运行结果:


1

2

3

4

5

6

7


牛呼吸空气

羊呼吸空气

猪呼吸空气

鱼呼吸水

我们会发现如果这样修改花销是很大的,除了将原来的类分解之外,还需要修改客户端。而直接修改类Animal来达成目的虽然违背了单一职责原则,但花销却小的多,代码如下:

1 class Animal{
2     public void breathe(String animal){
3         if("鱼".equals(animal)){
4             System.out.println(animal+"呼吸水");
5         }else{
6             System.out.println(animal+"呼吸空气");
7         }
8     }
9 }

1 public class Client{
2     public static void main(String[] args){
3         Animal animal = new Animal();
4         animal.breathe("牛");
5         animal.breathe("羊");
6         animal.breathe("猪");
7         animal.breathe("鱼");
8     }
9 } 

可以看到,这种修改方式要简单的多。但是却存在着隐患:有一天需要将鱼分为呼吸淡水的鱼和呼吸海水的鱼,则又需要修改Animal类的breathe方法,而对原有代码的修改会对调用“猪”“牛”“羊”等相关功能带来风险,也许某一天你会发现程序运行的结果变为“牛呼吸水”了。这种修改方式直接在代码级别上违背了单一职责原则,虽然修改起来最简单,但隐患却是最大的。还有一种修改方式:

1 class Animal{
2     public void breathe(String animal){
3         System.out.println(animal+"呼吸空气");
4     }
5
6     public void breathe2(String animal){
7         System.out.println(animal+"呼吸水");
8     }
9 }

1 public class Client{
2     public static void main(String[] args){
3         Animal animal = new Animal();
4         animal.breathe("牛");
5         animal.breathe("羊");
6         animal.breathe("猪");
7         animal.breathe2("鱼");
8     }
9 } 

可以看到,这种修改方式没有改动原来的方法,而是在类中新加了一个方法,这样虽然也违背了单一职责原则,但在方法级别上却是符合单一职责原则的,因为它并没有动原来方法的代码。这三种方式各有优缺点,那么在实际编程中,采用哪一中呢?其实这真的比较难说,需要根据实际情况来确定。我的原则是:只有逻辑足够简单,才可以在代码级别上违反单一职责原则;只有类中方法数量足够少,才可以在方法级别上违反单一职责原则;

例如本文所举的这个例子,它太简单了,它只有一个方法,所以,无论是在代码级别上违反单一职责原则,还是在方法级别上违反,都不会造成太大的影响。实际应用中的类都要复杂的多,一旦发生职责扩散而需要修改类时,除非这个类本身非常简单,否则还是遵循单一职责原则的好。

遵循单一职责原的优点有:

  • 可以降低类的复杂度,一个类只负责一项职责,其逻辑肯定要比负责多项职责简单的多;
  • 提高类的可读性,提高系统的可维护性;
  • 变更引起的风险降低,变更是必然的,如果单一职责原则遵守的好,当修改一个功能时,可以显著降低对其他功能的影响。

需要说明的一点是单一职责原则不只是面向对象编程思想所特有的,只要是模块化的程序设计,都适用单一职责原则。

参考:设计模式六大原则

时间: 2024-10-26 23:25:52

设计模式六大原则(1):单一职责原则的相关文章

学习设计模式 - 六大基本原则之单一职责原则

设计模式总共有六大基本原则,统称为SOLID (稳定)原则,分别是S-单一职责原则(Single Responsibility Principle), O-开闭原则(Open closed Principle),L-里氏替换原则(Liskov Substitution Principle),L-迪米特法则(Law of Demeter),I-接口隔离原则(Interface Segregation Principle),D-依赖倒置原则(Dependence Invension Principl

面向对象编程6大设计原则:单一职责原则

单一职责原则(Single  Responsibility Principle)简称SRP原则. 定义 应该有且仅有一个原因引起类的变更. 优点 可以降低类的复杂度,一个类只负责一项职责,其逻辑肯定要比负责多项职责简单的多: 提高类的可读性,提高系统的可维护性: 变更引起的风险降低,变更是必然的,如果单一职责原则遵守的好,当修改一个功能时,可以显著降低对其他功能的影响. 说明 单一职责原则不只是面向对象编程思想所特有的,只要是模块化的程序设计,都适用单一职责原则: 单一职责原则要根据项目的实际情

面向对象设计原则:单一职责原则(The Single Responsibility Principle)

热爱生活.享受娱乐.专注技术,欢迎关注微信公众号QGer,我们一起见证成长! 什么是单一职责原则? - 官方解释:一个类应该只有一种改变的原因 - 通俗解释:一个类被修改.拓展的时候,应该只能因为一种职责(功能)的扩展,而不应该有第二种职责导致类的修改,一个也不能有另一种职责存在. 为什么遵循单一职责原则? 降低类的复杂度,一个类负责一种职责,逻辑上也变得直观简单. 使代码变得灵活,提高系统的维护性. 变更的风险降低,有需求就会有变更,单一职责原则可降低变更的影响面. 保持松耦合,提供内聚. 如

设计模式六大原则之单一职责原则

一.什么是设计模式 设计模式:设计模式(Design pattern)是一套被反复使用.多数人知晓的.经过分类编目的.代码设计经验的总结.由此可见,设计模式不是代码复用而是经验复用.是代码设计的经验总结. 设计模式的六大原则:[单一职责.里氏替换.依赖倒置.接口隔离.迪米特法则.开闭] 23中常用的设计模式: [单例模式.工厂模式.抽象工厂模式.模板模式.代理模式.建造者模式.原型模式.中介者模式. 命令模式.装饰模式.策略模式.责任链模式.适配模式.迭代器模式.组合模式.观察者模式.备忘录模式

设计模式(三)面向对象设计原则之单一职责原则

引用自:http://blog.csdn.net/lovelion  作者:刘伟 单一职责原则是最简单的面向对象设计原则,它用于控制类的粒度大小.单一职责原则定义如下: 单一职责原则(Single Responsibility Principle, SRP):一个类只负责一个功能领域中的相应职责, 或者可以定义为:就一个类而言,应该只有一个引起它变化的原因. 单一职责原则告诉我们:一个类不能太"累"!在软件系统中,一个类(大到模块,小到方法)承担的 职责越多,它被复用的可能性就越小,而

面向对象五大原则_1.单一职责原则&2.里氏替换原则

单一职责原则:Single Responsibility Principle (SRP) 一个类.仅仅有一个引起它变化的原因.应该仅仅有一个职责.每个职责都是变化的一个轴线.假设一个类有一个以上的职责,这些职责就耦合在了一起.这会导致脆弱的设计.当一个职责发生变化时,可能会影响其他的职责.另外,多个职责耦合在一起,会影响复用性. 比如:要实现逻辑和界面的分离. T负责两个不同的职责:职责P1.职责P2.当因为职责P1需求发生改变而须要改动类T时.有可能会导致原本执行正常的职责P2功能发生问题.

day01_面向对象五大原则_1.单一职责原则&2.里氏替换原则

单一职责原则:Single Responsibility Principle (SRP) 一个类,只有一个引起它变化的原因.应该只有一个职责.每一个职责都是变化的一个轴线,如果一个类有一个以上的职责,这些职责就耦合在了一起.这会导致脆弱的设计.当一个职责发生变化时,可能会影响其它的职责.另外,多个职责耦合在一起,会影响复用性.例如:要实现逻辑和界面的分离. T负责两个不同的职责:职责P1,职责P2.当由于职责P1需求发生改变而需要修改类T时,有可能会导致原本运行正常的职责P2功能发生故障.也就是

设计原则之单一职责原则

定义:一个类只负责一项职责,应该只有一个能引起它变化的原因. 问题:类T负责两个不同的职责:职责P1,职责P2.当由于职责P1需求发生改变而需要修改类T时,有可能会导致原本运行正常 的职责P2功能发生故障. 解决:分别建立两个类T1.T2,使T1完成职责P1功能,T2完成职责P2功能.这样,当修改类T1时,不会使职责P2发生故障风险: 同理,当修改T2时,也不会使职责P1发生故障风险. 举个栗子:介绍几种动物的栖息地和食物,这里边有两项职责:栖息地和食物. 用一个类Recommend介绍牛生活在

6大设计原则(1):单一职责原则

定义:应该且仅有一个原因引起类的变更. 理解: 如果一个类承担的职责过多,就等于把这些职责耦合在一起,一个职责的变化可能会削弱或者抑制这个类完成其他职责的能力, 这种耦合会导致脆弱的设计.当变化发生时,设计会遭受到意想不到的破坏. 假如一个类A,有两个职责a,b,当职责a由于需求发生变化而需要修改时,有可能会导致职责b的功能发生故障. 解决: 将类中的职责分开,分别建立两个类. 如果是面向接口编程的话,就是将两个职责抽象成为两个不同的接口,原接口再实现这两个接口. 单一职责原则的好处: 1.类的

面向对象设计原则之单一职责原则(SRP)

Web程序猿博客:http://blog.csdn.net/thinkercode 这条原则曾经在 Tom DeMaro 和 Meilir Page-Jones 的著作中描述过,并称之为内聚性(cohesion).他们把内聚性定义为:一个模块的组成元素之间的功能相关性. 单一职责原则(SRP) 单一职责原则(Single Responsibility Principle, SRP):就一个类而言,应该仅有一个引起它变化的原因. 单一职责的原则告诉我们:在软件系统中,如果一个类承担的职责过多,就等