01-单一职责原则(SPR)

1. 背景

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

2. 定义

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

3. 宏观上

   类层次上存在单一职责原则,同样方法层次上也存在单一职责原则。

4. 补充两个概念

   高内聚:内聚是指类内部的属性和行为,高内聚就是指:一个类的属性和行为与这个类非常密切,称为高内聚。
   低耦合:耦合是指类与类之间或者模块与模块之间的联系,低耦合就是指:耦合度低,易重用、使用灵活。

5. 案例

 需求一:有牛和羊两种动物,它们都需要呼吸空气。

    解决思路:构造动物类,封装呼气空气的方法。

 1  public class Animal
 2     {
 3         public string myName { get; set; }
 4 
 5         private string _name = null;
 6         public Animal()
 7         {
 8 
 9         }
10         public Animal(string name)
11         {
12             this._name = name;
13         }
14 
15         //封装呼吸空气的方法
16         public void BreathAir()
17         {
19               Console.WriteLine(this._name + "呼吸空气");
21         }
22     }

 需求变更:又多了鱼这个物种,它们需要呼吸空气。

   解决方案一:直接在BreathAir上加判断,但是这样违背了方法意义上的单一职责原则

 1    public void BreathAir()
 2         {
 3             if (this._name.Equals(""))
 4             {
 5                  Console.WriteLine(this._name + "呼吸水");   //违背了方法级别的单一职责
 6             }
 7             else
 8             {
 9                 Console.WriteLine(this._name + "呼吸空气");
10             }
11         }

  解决方案二:在Animal类中添加一个BreathWater的方法,但是这样违背了类意义上的单一职责原则

1        //封装呼吸水的方法
2         public void BreathWater()
3         {
4             Console.WriteLine(this._name + "呼吸水");
5         } 

     解决方案三:新建一个WaterAnimal类,在里面封装BreathWater的方法,无论是类级别还是方法级别,都满足了单一职责原则,但是改动成本太大,耗时太长。

 1   public class WaterAnimal
 2     {
 3          private string _name = null;
 4          public WaterAnimal(string name)
 5         {
 6             this._name = name;
 7         } 
 8         //封装呼吸水的方法
 9         public void BreathWater()
10         {
11             Console.WriteLine(this._name + "呼吸水");
12         }
13     }

 综合调用:

 1        public static void show()
 2         {
 3             //下面模拟单一职责面对需求变更的情况。
 4             //需求1:有牛和羊两种动物,它们需要呼吸空气
 5             //解决思路:构造动物类→封装呼吸空气的方法
 6             Animal animal1 = new Animal("");
 7             Animal animal2 = new Animal("");
 8             animal1.BreathAir();
 9             animal2.BreathAir();
10 
11             //需求2:又多了鱼这个物种,它们需要呼吸水
12             //解决方案一:在Breath里加判断,但是违背了方法级别的单一职责原则
13             Animal animal3 = new Animal("");
14             animal3.BreathAir();
15 
16             //解决方案二:在Animal类中添加一个BreathWater的方法,但是违背了类级别的单一职责原则
17             Animal animal4 = new Animal("");
18             animal4.BreathWater();
19 
20             //解决方案三:新建一个WaterAnimal类,在里面封装BreathWater的方法,无论是类级别还是方法级别,都满足了单一职责原则,但是改动成本太大,耗时太长
21             WaterAnimal animal5 = new WaterAnimal("");
22             animal5.BreathWater();
23 
24         }

  解决方案四:利用委托来解决。

 1         /// <summary>
 2         /// 利用委托的插件式编程
 3         /// </summary>
 4         public static void show2()
 5         {
 6             Console.WriteLine("------------------下面是利用委托来解决--------------------");
 7             Animal animal1 = new Animal() { myName = "" };
 8             Animal animal2 = new Animal() { myName = "" };
 9             Animal animal3 = new Animal() { myName = "" };
10             Action<Animal> act1 = Utils.BreathWater;
11             Action<Animal> act2 = Utils.BreathAir;
12             act1.Invoke(animal1);
13             act1.Invoke(animal2);
14             act2.Invoke(animal3);
15         }

6. 单一职责原则的好处

 (1). 降低类复杂性,一个类只负责一项职责要比负责多项职责简单的多。

   (2). 提高类的可读性,便于维护。

   (3). 变更引起的风险低,修改一个类的功能,显著降低对其他类的影响。

7. 我的总结

    如果完全遵循单一职责原则,当业务复杂的时候,改动成本是最大的。所以我的原则是:根据实际业务场景,来决定是否违背方法或类层次上的单一职责原则。

原文地址:https://www.cnblogs.com/yaopengfei/p/7101344.html