C++单一职责原则示例代码浅析
作者:北冥有鱼丶丶
我们在设计一个类时要学会发现职责,并把那些职责相互分离,其实要去判断是否应该分离出一个类来并不难,前面说过,一个类应该只有一个引起它变化的原因,如果你能想到其它的原因也能去改变这个类,那么这个类就具有多于1个的职责,就应该考虑类的职责分离
单一职责原则:
就一个类而言,应该只有一个引起它变化的原因,如果一个类承担的职责过多就等于把这些职责耦合在一起,至少会造成以下两方面的问题:
- 我们要去修改该类中的一个职责可能会影响到该类的其它职责。这种耦合会导致脆弱的设计,当变化发生时,设计会遭受到意想不到的破坏。
- 当客户端仅需要该对象的某一个职责时,不得不将其他不需要的职责全都包含进来,从而造成冗余代码或代码的浪费。
我们在设计一个类时要学会发现职责,并把那些职责相互分离,其实要去判断是否应该分离出一个类来并不难,前面说过,一个类应该只有一个引起它变化的原因,如果你能想到其它的原因也能去改变这个类,那么这个类就具有多于1个的职责,就应该考虑类的职责分离。
在之前的这篇博客中,传送门,我们实现的计算器实际上也用到了单一职责原则,这里我们选出其中最经典的3.0版本和5.0版本来学习单一职责原则。
3.0版本计算器代码如下:
#include<iostream> using namespace std; #include<string> //业务逻辑 //异常类用于处理异常情况 class opeException { public: void getMessage() { cout << "您的输入有误!" << endl; } }; //运算类用于处理运算 class Operation { public: Operation(string& _num1, string& _num2, string& _ope) :num1(_num1), num2(_num2), ope(_ope){} //获取运算结果 int getResult() { if (!(isStringNum(num1) && isStringNum(num2) && (ope == "+" || ope == "-" || ope == "*" || ope == "/"))) throw opeException(); if (ope == "+") { re = stoi(num1) + stoi(num2); } else if (ope == "-") { re = stoi(num1) - stoi(num2); } else if (ope == "*") { re = stoi(num1) * stoi(num2); } else if (ope == "/") { if (stoi(num2) != 0) { re = stoi(num1) / stoi(num2); } else throw opeException(); } return re; } private: int re; string num1; string num2; string ope; //判断一个字符串是不是数字 bool isStringNum(string& s) { bool flag = true; for (auto e : s) if (!(isdigit(e))) { flag = false; break; } return flag; } }; //界面逻辑 int main() { try { string _num1 = " "; string _num2 = " "; string _ope = " "; cout << "请输入左操作数:" << endl; cin >> _num1; cout << "请输入右操作数:" << endl; cin >> _num2; cout << "请输入操作符" << endl; cin >> _ope; Operation operation(_num1, _num2, _ope); cout << operation.getResult() << endl; } catch (opeException &ex) { ex.getMessage(); } return 0; }
仅仅一个运算类Operation就实现了加减乘除4种功能,很明显在这个类中我至少有4个原因去修改这个类,我修改加法算法的时候可能会影响到其它的运算算法,这个类的耦合太高且严重违反了单一职责原则。
修改后的5.0版本如下:
#include<iostream> using namespace std; #include<string> //业务逻辑 //异常类用于处理异常情况 class opeException { public: void getMessage() { cout << "您的输入有误!" << endl; } }; //运算类 class Operation { //判断一个字符串是不是数字 bool isStringNum(string& s) { bool flag = true; for (auto e : s) if (!(isdigit(e))) { flag = false; break; } return flag; } protected: bool isError(string& _strNum1, string& _strNum2, string& _ope) { if (!(Operation::isStringNum(_strNum1) && Operation::isStringNum(_strNum2) && (_ope == "+" || _ope == "-" || _ope == "*" || _ope == "/"))) { return false; } } public: virtual int getResult() = 0; }; //加法运算类 class addOperation :public Operation { private: string strNum1; string strNum2; string ope; int re; public: addOperation(string& _strNum1, string& _strNum2, string& _ope) :strNum1(_strNum1), strNum2(_strNum2), ope(_ope), re(0) {} virtual int getResult() override { if (!isError(strNum1, strNum2, ope)) throw opeException(); else re = stoi(strNum1) + stoi(strNum2); return re; } }; //减法运算类 class subOperation :public Operation { private: string strNum1; string strNum2; string ope; int re; public: subOperation(string& _strNum1, string& _strNum2, string& _ope) :strNum1(_strNum1), strNum2(_strNum2), ope(_ope), re(0) {} virtual int getResult() override { if (!isError(strNum1, strNum2, ope)) throw opeException(); else re = stoi(strNum1) - stoi(strNum2); return re; } }; //乘法运算类 class mulOperation :public Operation { private: string strNum1; string strNum2; string ope; int re; public: mulOperation(string& _strNum1, string& _strNum2, string& _ope) :strNum1(_strNum1), strNum2(_strNum2), ope(_ope), re(0) {} virtual int getResult() override { if (!isError(strNum1, strNum2, ope)) throw opeException(); else re = stoi(strNum1) * stoi(strNum2); return re; } }; //除法运算类 class divOperation :public Operation { private: string strNum1; string strNum2; string ope; int re; public: divOperation(string& _strNum1, string& _strNum2, string& _ope) :strNum1(_strNum1), strNum2(_strNum2), ope(_ope), re(0) {} virtual int getResult() override { if (!isError(strNum1, strNum2, ope)) throw opeException(); else if (stoi(strNum2) != 0) re = stoi(strNum1) / stoi(strNum2); else throw opeException(); return re; } }; //运算工厂类 class OpeFactory { public: Operation& choose(string &_strNum1,string &_strNum2,string &_ope) { if (_ope == "+") { operation = new addOperation(_strNum1, _strNum2, _ope); } else if (_ope == "-") operation = new subOperation(_strNum1, _strNum2, _ope); else if (_ope == "*") operation = new mulOperation(_strNum1, _strNum2, _ope); else if (_ope == "/") { operation = new divOperation(_strNum1, _strNum2, _ope); } else operation = nullptr; return *operation; } private: Operation* operation; }; //界面逻辑 int main() { try { string _strNum1 = " "; string _strNum2 = " "; string _ope = " "; cout << "请输入左操作数:" << endl; cin >> _strNum1; cout << "请输入右操作数:" << endl; cin >> _strNum2; cout << "请输入操作符:" << endl; cin >> _ope; OpeFactory factory; Operation* re = &factory.choose(_strNum1, _strNum2, _ope); if (re != nullptr) cout << (*re).getResult() << endl; else cout << "您的输入有误!" << endl; } catch (opeException ex) { cout << "您的输入有误" << endl; } return 0; }
在5.0版本的计算器代码中,我们将运算类分成了4种类,分别是加法类、减法类、乘法类、除法类,还创建了一个工厂类专门用于根据不同情况实例化对象,每个类只有一个职责,我们要修改某个功能只需要去修改对应的类即可,极大降低了代码之间的耦合。
单一职责原则的核心就是控制类的粒度大小、将对象解耦、提高其内聚性。如果遵循单一职责原则将有以下优点:
- 降低类的复杂度。一个类只负责一项职责,其逻辑肯定要比负责多项职责简单得多。
- 提高类的可读性。复杂性降低,自然其可读性会提高。
- 提高系统的可维护性。可读性提高,那自然更容易维护了。
- 变更引起的风险降低。变更是必然的,如果单一职责原则遵守得好,当修改一个功能时,可以显著降低对其他功能的影响。
到此这篇关于C++单一职责原则示例代码浅析的文章就介绍到这了,更多相关C++单一职责原则内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!