择百家之言,无一己之思。记刍荛之见,防他日忘之。
设计模式六大原则——单一职责原则
概念
单一职责原则:又称为单一功能原则,它规定一个类应该只有一个发生变化的原因。
所谓的职责是指单一变化的原因。如果一个类有多于一个的动机被改变,那么这个类就具有多于一个的职责。而单一职责原则就是指一个类或者模块应该有且只有一个改变的原因。问题描述
一个类负责两个不同的职责,当其中一个职责因为需求的改变而要修改的时候,有可能会导致原本正常的职责功能也发生故障,也就是说这两个职责被耦合在一起了。
产生原因
单一职责原则大家可能都觉得比较简单,一个类或者一个功能模块只负责一件事情,没有一个Coder不知道应该写出高内聚低耦合的程序,但是很多情况都是发生在不经意之间。可能之前设计了一个功能T只负责一个职责P,但是由于需求的变动,P被分成了颗粒度更小的职责P1和P2。这种情况被称为职责扩散,在职责扩散的情况下,之前程序设计中的单一职责原则也就被打破了。
解决办法
时刻遵守单一职责原则,将不同的职责封装到不同的类或者模块中。 当有新的需求将现有的职责分为颗粒度更小的职责的时候,应该及时对现有代码进行重构。
实例
用一个类来描述汽车加油这个场景。
class Car { public : void Refueling(std::string strCar) { cout << strCar.c_str() << " 加汽油" << endl; } }; int main() { Car objCar; objCar.Refueling("公共汽车"); objCar.Refueling("出租汽车"); objCar.Refueling("私家车"); return 0; }
输出内容:
公共汽车 加汽油
出租汽车 加汽油
私家车 加汽油。
但是随着国家对环保的重视和国民环保意识的提高,电瓶车作为代步工具开始火起来了。这时候再用这个类描述这个场景有如下几种实现方式:
- 方式一
class Car { public: void Refueling(std::string strCar) { if (strCar.compare("电瓶车")) { cout << strCar.c_str() << " 充电" << endl; } else { cout << strCar.c_str() << " 加汽油" << endl; } } };
或者
class Car { public: enum TYPE {ELECTRICITY,GASOLINE}; void Refueling(std::string strCar,TYPE type) { switch (type) { case TYPE::ELECTRICITY: cout << strCar.c_str() << " 充电" << endl; break; case TYPE::GASOLINE: cout << strCar.c_str() << " 加汽油" << endl; break; default: break; } } };
这种方式很明显没有遵循单一职责原则。无论是电瓶车需要修改还是加汽油的车需要修改,都要改变Car这个类,证明引起这个类发生变化的原因已经不唯一。接下来有了方式二:
- 方式二
class Car { public: void GasRefueling(std::string strCar) { cout << strCar.c_str() << " 加汽油" << endl; } void EleRefueling(std::string strCar) { cout << strCar.c_str() << " 充电" << endl; } }
这种方式虽然也违背了单一职责原则,但是从方法级别上来说确实符合单一职责原则的。因为它并没有动原来的代码。
接下来看方式三:
class Car { public: virtual void Refueling(string strCar) = 0; }; class ElectricityCar : public Car { public : virtual void Refueling(std::string strCar) { cout << strCar.c_str() << " 充电" << endl; } }; class GasolineCar : public Car { public: virtual void Refueling(std::string strCar) { cout << strCar.c_str() << " 加汽油" << endl; } };
这种方式是符合单一原则的,但是如果仅仅是因为这么一个方法而动用这么多的代码和时间是不是值得的?这三种方式各自有各自的优缺点。当原有的单一原则被打破需要重构的时候,选择合适的重构方式很重要。根据功能逻辑的简易和功能方法的多少选择合适的重构方法。
一言以蔽之,遵循单一原则可以降低类的复杂度,提高类的可读性和系统的可维护性。它不仅仅是面向对象程序所特有的,只要是模块话的程序设计,都是用单一职责原则!