欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

设计模式之单一职责原则

程序员文章站 2022-06-18 16:44:13
定义:不要存在多于一个导致类变更的原因。通俗地说,即一个类只负责一项职责。 问题由来:类T负责两个不同的职责:职责P1,职责P2。当由于职责P1需求发生改变而需要修改类T时,有可能导致原本运行正常的职责P2功能发生故障。 解决方案:遵循单一职责原则。分别建立两个类T1、T2。这样修改时互不影响。 很 ......

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

问题由来:类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)