一、单一职责原则

  单一职责原则指的是,在程序设计时,一个类或者一个接口的应该职责是唯一的。于此对应的,只有某种特定的原因,才能引起类或者接口的变动。单一职责原则要求我们不要设计大而全的接口,而是将其拆分为多个接口,每个接口只负责单一的职责。这样做有如下几个优点:

  • 容易复用。一个类设计的越臃肿,复用它的概率就越低,反之则越改。
  • 提升内聚性,降低耦合性。一个类承担的职责越多,那么相当于很多功能就被耦合到了一起,一个职责发生变动时,其他职责受到的影响也就越大。
  • 单一职责的接口容易维护,反之则不容易维护。

示例:

  为了查询查询NBA中球队的一些数据进行展示,需要开发一个程序,这个程序包含三个步骤,向数据库查询球队数据,对查回来的数据进行处理,展示数据。

  不符合单一职责原则的设计:

 1 class NBATeamDataDisplay
 2 {
 3     public:
 4         /* 向数据库查询数据*/
 5         void queryTeamData();
 6 
 7         /* 处理查回来的数据*/
 8         void handleTeamData();
 9 
10         /* 展示处理查回来的数据*/
11         void showTeamData();
12 }

  上面设计的这个类不符合单一职责原则,NBATeamDataDisplay这个类同时承担了查询数据,处理书籍,展示数据三个职责,三个职责耦合在一起,其中一个职责如果发生修改,这个类都会受影响,维护起来比较困难。

  符合单一职责原则的设计:

 1 class NBATeamDataQuery
 2 {
 3     public:
 4         /* 向数据库查询数据*/
 5         void queryTeamData();  
 6 }
 7 
 8 class NBATeamDataHandle
 9 {
10     public:
11         /* 向数据库查询数据*/
12         void handleTeamData();  
13 }
14 
15 class NBATeamDataDisplay
16 {
17     public:
18         /* 展示处理查回来的数据*/
19         void showTeamData();
20 }

  我们可以将最初NBATeamDataDisplay这个类拆分成NBATeamDataQuery, NBATeamDataHandle, NBATeamDataDisplay三个类,分别对应,查询,数据处理,展示三个功能,这样,三个不同功能被隔离开来,更容易维护。

   

二、开闭原则

  开闭原则是面向对象设计的第一基石,它指的是,系统设计应对扩展开放,对修改关闭。即对系统的改动应该尽量不涉及源码的改动。任意一个程序或软件,在开发的过程中,难免遇到需求变更的情况,这时应该尽量避免修改到原来的代码。因为修改意味着不确定性,在软件开发的过程中,要尽可能的消除不确定性,才能实现系统架构的稳定。

  在《设计模式的艺术》这本书中提到,要实现开闭原则,就需要对系统进行抽象化设计。可以为系统分为抽象层和实现层,这个抽象层相对稳定,描述对象一些共性的特征,而具体对象具体的具体行为,可以放到实现层中实现。

示例:

  有一家书店有一个图书管理系统,可以用这个系统管理售卖的书。当前书店正在搞活动,历史类的数据打八折,艺术类的书打八折。现在需要根据这个活动,对图书管理系统进行修改。

  不符合开闭原则的设计:

 1 // 修改前
 2 class bookManager
 3 {
 4     private:
 5         double oriPrice;
 6     public:
 7         double getPrice(std::string bookType)
 8         {
 9             return oriPrice;
10         }
11 }
12 // 修改后
13 class bookManager
14 {
15     private:
16         double oriPrice;
17     public:
18         double getPrice(std::string bookType)
19         {
20             if(bookType == "history")
21             {
22                 return 0.8*oriPrice;
23             }
24             else if(bookType == "act")
25             {
26                 return 0.7*oriPrice;
27             }
28             else
29             {
30                 return oriPrice;
31             }
32             
33         }
34 }

  上面这个代码是不符合开闭原则的,要修改历史和艺术类谁的售价,必须修改bookManger这个类的源码,这样,理论上所有用到bookManger这个类的代码都会收到影响。

    符合开闭原则的设计:

 1 //抽象的图书管理程序
 2 class bookManager
 3 {
 4     protected:
 5         double oriPrice;
 6     public:
 7         virtual double getPrice() = 0;
 8 };
 9 
10 //具体的图书管理程序
11 class normalBookManger:public bookManager
12 {
13     public:
14         double getPrice() override
15         {
16             return oriPrice;
17         }
18 };
19 
20 class historyBookManager:public bookManager
21 {
22     public:
23     double getPrice() override
24     {
25         return oriPrice*0.8;
26     }
27 };
28 
29 class actBookManager:public bookManager
30 {
31     public:
32     double getPrice() override
33     {
34         return oriPrice*0.7;
35     }
36 };

  上面这个设计中,将bookManger这个类提取出来,成为一个抽象的类,它的具体实现成了某一类具体书的管理器。这样,再实现新功能时,只需要新增两个类hsitoryBookManger和actBookManager两个新的实现,不会影响到原来的类normalBookManager,减小了影响的范围。