一、单一职责原则
单一职责原则指的是,在程序设计时,一个类或者一个接口的应该职责是唯一的。于此对应的,只有某种特定的原因,才能引起类或者接口的变动。单一职责原则要求我们不要设计大而全的接口,而是将其拆分为多个接口,每个接口只负责单一的职责。这样做有如下几个优点:
- 容易复用。一个类设计的越臃肿,复用它的概率就越低,反之则越改。
- 提升内聚性,降低耦合性。一个类承担的职责越多,那么相当于很多功能就被耦合到了一起,一个职责发生变动时,其他职责受到的影响也就越大。
- 单一职责的接口容易维护,反之则不容易维护。
示例:
为了查询查询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,减小了影响的范围。