单一职责原则

来源:互联网 发布:知乎rss订阅地址 编辑:程序博客网 时间:2024/06/08 15:26

单一职责原则的定义比较简单——对于一个类,应该只有一个引起它变化的原因。

当我们在进行软件开发的时候,经常会给已经设计的一个类新增各种各样的功能,或许是出于需求变更,或许是因为出于开发量的考量,一个类就在这样或那样的原因下变得逐渐臃肿庞大而且不方便管理。例如一个负责接受用户发来信息的类,也被设计为可以访问数据库将用户发来的信息进行记录等等,这意味着,当接收用户发送信息的结构变化或数据库持久层变化都会引起类的变化,而这就违背了类的单一职责原则。

举个例子,我们设计一个超人SuperMan类,超人就应该能人所不能,所以设计给他尽可能多的功能。

/**  * Author:小青  * Time:2017-8-26   * Function:无所不能的超人类  *  */public class SuperMan{public void worldPeace(){System.out.println("超人可以维护世界和平");}public void writeCode(){System.out.println("超人能写代码");}public void writeBook(){System.out.println("超人能写小说");}public void playGanme(){System.out.println("超人打LOL上王者");}public void other(){System.out.println("超人还有其他数不清的功能");}}
这样设计出来的超人可以说是非常强悍的,什么都会,但与此同时,我们发现,由于LOL版本更新,超人需要重新修改下玩LOL 的代码,在这个修改期间,很多的罪犯出来捣乱了,而超人却还在维修,于是我们需要重新考虑设计超人的问题,只有超人可以维护世界和平的情况下,因为LOL而拉回去改造是不是很不合适呢?所以我们减少超人的职责负担。
/**  * Author:小青  * Time:2017-8-26   * Function:维护世界和平的超人类  *  */public class SuperMan{public void worldPeace(){System.out.println("超人可以维护世界和平");}}
为什么类应该满足单一职责原则呢?首先,易于维护的高度可复用性是面向对象开发的突出优点,如果一个类职责过于庞大,维护起来必然是困那重重,我们需要尽可能多的创造复用代码,所以当类的职责过于庞大的时候,就与面向对象的思想背道而驰了,类的合理性也就不用在提。

但即使经验丰富的开发人员也不可避免的会违背单一职责这一原则,这就是因为职责扩散。职责扩散是因为某些原因,职责A被分化为粒度更细的职业A1和A2。举个例子

/**  * Author:小青  * Time:2017-8-26   * Function:动物的呼吸功能  *  */public class Animal{public void breathe(String animal){system.out.println(animal + "呼吸空气");}}public class Client{public sttaic void main(String[] args){Animal animal = new Animal();animal.breathe("猫");animal.breathe("狗");animal.breathe("羊");}}
程序在运行时候发现,并不是所有的动物都呼吸空气的,比如鱼。修改的时候如果遵循单一职责原则,就需要将动物细分为陆生动物类和水生动物类

/**  * Author:小青  * Time:2017-8-26   * Function:陆生动物呼吸空气  *  */public class Terrestrial{public void breathe(String animal){system.out.println(animal + "呼吸空气");}}/**  * Author:小青  * Time:2017-8-26   * Function:水生动物在水中呼吸  *  */public class Aquatic{public void breathe(String animal){system.out.println(animal + "在水中呼吸");}}public class Client{public sttaic void main(String[] args){Terrestrial animal = new Terrestrial();animal.breathe("猫");animal.breathe("狗");animal.breathe("羊");Aquatic aquatic = new Aquatic();aquatic.breathe("鱼");}}
代码改动后结构如下,除了将Animal修改为Terrestrial和Aquaticlian两个类意外,还包括对客户端代码的修改,而直接修改Animal类虽然违背了单一职责原则,对资源的开

销反而更小。

/**  * Author:小青  * Time:2017-8-26   * Function:动物的呼吸功能  *  */public class Animal{public void breathe(String animal){if("鱼".equals(animal)){system.out.println(animal + "在水中呼吸");}else{system.out.println(animal + "呼吸空气");}}}public class Client{public sttaic void main(String[] args){Animal animal = new Animal();animal.breathe("猫");animal.breathe("狗");animal.breathe("羊");animal.breathe("鱼");}}
这样修改相对更加简单,但是如果不仅仅只有许需要在水中呼吸,还有虾,螃蟹等等其他的水生物呢?所以这样的方式是存在隐患的,这种修改方式在代码级别上违背了单

一职责原则,虽然看起来操作最简单,但是隐患也是最大的。

/**  * Author:小青  * Time:2017-8-26   * Function:动物的呼吸功能  *  */public class Animal{public void breathe(String animal){system.out.println(animal + "呼吸空气");}public void breathe2(String animal){system.out.println(animal + "在水中呼吸");}}public class Client{public sttaic void main(String[] args){Animal animal = new Animal();animal.breathe("猫");animal.breathe("狗");animal.breathe("羊");animal.breathe2("鱼");}}
这种方式在不改动原有方法的基础上,新增了一个方法,这样在方法级别上是满足单一职责原则的。以上三种方式各有优缺点,在实际开发中要有选择的使用,有一种原则

:需要足够简单的逻辑才能在代码级别上违背单一职责原则,类中方法足够少才能在方法级别上违背单一职责原则。

单一职责原则可以降低类的复杂度,一个类只负责一个职责,其逻辑肯定要比负责多项职责简单,提高类的可读性,提高系统的可维护性。

面向对象的编程几乎就是一个发现职责并将其互相分离的过程,至于如何做到,如果能想到多余一个动机去改变一个类,那么这个类就多余一个职责,需要我们将其分离开

来。

以上内容,整理自刘径舟,张玉华编著的《设计模式其实很简单》读书笔记,欢迎转载.