引入:利用C++、Java、C#或VB.NET任意一种面向对象语言实现一个计算器控制程序,要求输入两个数和运算符号,得到结果。
一、最粗糙实现版本(Calculator01):
#include#include using namespace std; int main() { cout << "Please enter the first number:" << endl; double firstNumber; cin >> firstNumber; cout << "Please enter the Second number:" << endl; double secondNumber; cin >> secondNumber; cout << "Please select calculation method: '+ - * / '" << endl; string method; cin >> method; if (method == "+") { cout << firstNumber + secondNumber << endl; } if (method == "-") { cout << firstNumber - secondNumber << endl; } if (method == "*") { cout << firstNumber * secondNumber << endl; } if (method == "/") { cout << firstNumber / secondNumber << endl; } system("pause"); return 0; }
看似可以实现功能,但是存在以下问题:
1.多次使用if分支判断,让计算机做无用的判断;
2.如果输入了0的除数,或者输入了字符符号而不是数字,程序会出错。
二、针对上述问题改进版(Calculator02):
#include#include using namespace std; int main() { cout << "Please enter the first number:" << endl; double firstNumber; cin >> firstNumber; cout << "Please enter the Second number:" << endl; double secondNumber; cin >> secondNumber; cout << "Please select calculation method: '+ - * / '" << endl; char method; cin >> method; switch (method) { case '+': cout << firstNumber + secondNumber << endl; break; case '-': cout << firstNumber - secondNumber << endl; break; case '*': cout << firstNumber * secondNumber << endl; break; case '/': if (secondNumber != 0) { cout << firstNumber / secondNumber << endl; break; } else { cout << "Divisor cannot be 0." << endl; break; } default: break; } system("pause"); return 0; }
目前,虽然可以实现计算器的功能。但是没有用到面向对象的思想,只是一股脑在main函数中把所有的功能进行堆砌。代码复用性低。
三、类封装后的计算器(Calculator03):
将业务逻辑与界面逻辑分开,降低之间的耦合度。将计算器类进行封装。
#includeusing namespace std; class Calculator { public: Calculator() = default; ~Calculator() = default; void getResult(double firstNum, double secondNum, char method) { switch (method) { case '+': cout << firstNum + secondNum << endl; break; case '-': cout << firstNum - secondNum << endl; break; case '*': cout << firstNum * secondNum << endl; break; case '/': if (secondNum != 0) { cout << firstNum / secondNum << endl; break; } else { cout << "Divisor cannot be 0." << endl; break; } default: break; } } }; int main() { cout << "Please enter the first number:" << endl; double firstNumber; cin >> firstNumber; cout << "Please enter the Second number:" << endl; double secondNumber; cin >> secondNumber; cout << "Please select calculation method: '+ - * / '" << endl; char method; cin >> method; Calculator c; c.getResult(firstNumber, secondNumber, method); system("pause"); return 0; }
现在,完成了计算器类的封装。但是如果需要增加一种新的运算方法,就需要对Switch分支进行增删、修改。若是复杂的程序,大量的修改可能会产生错误。因此继续使用继承来优化计算器程序。
四、颗粒度更细的计算器(Calculator04):
#includeusing namespace std; class AbsCalculator { public: AbsCalculator() = default; ~AbsCalculator() = default; virtual void calculateMethod(double firstnum, double secondNum){}; void setFirstNum(double firstNum) { this->firstNum = firstNum; } double getFirstNum() { return this->firstNum; } void setSecondNum(double secondNum) { this->secondNum = secondNum; } double getSecondNum() { return this->secondNum; } private: double firstNum; double secondNum; }; class addCalculator : public AbsCalculator { public: void calculateMethod(double firstNum, double secondNum) { cout << firstNum + secondNum << endl; } }; class subCalculator : public AbsCalculator { public: void calculateMethod(double firstNum, double secondNum) { cout << firstNum - secondNum << endl; } }; class multiCalculator : public AbsCalculator { public: void calculateMethod(double firstNum, double secondNum) { cout << firstNum * secondNum << endl; } }; class divCalculator : public AbsCalculator { public: void calculateMethod(double firstNum, double secondNum) { if (secondNum != 0) { cout << firstNum / secondNum << endl; } else { cout << "Divisor cannot be 0." << endl; } } };
定义一个抽象的计算器类,它拥有一个虚的计算方法,需要在子类中重写。
子类分别定义为加法计算器、乘法计算器、减法计算、除法计算器,继承抽象的计算器类。再分别实现对应的计算方法。
那么如何才能调用对应功能的计算器呢(如何实例化对象)?
五、通过简单工厂类来实例化对象:
#include#include using namespace std; //class AbsCalculator; //class addCalculator; //class subCalculator; //class multiCalculator; //class divCalculator; class AbsCalculator { public: AbsCalculator() = default; ~AbsCalculator() = default; virtual void calculateMethod(double firstnum, double secondNum) {}; void setFirstNum(double firstNum) { this->firstNum = firstNum; } double getFirstNum() { return this->firstNum; } void setSecondNum(double secondNum) { this->secondNum = secondNum; } double getSecondNum() { return this->secondNum; } private: double firstNum; double secondNum; }; class addCalculator : public AbsCalculator { public: void calculateMethod(double firstNum, double secondNum) { cout << firstNum + secondNum << endl; } }; class subCalculator : public AbsCalculator { public: void calculateMethod(double firstNum, double secondNum) { cout << firstNum - secondNum << endl; } }; class multiCalculator : public AbsCalculator { public: void calculateMethod(double firstNum, double secondNum) { cout << firstNum * secondNum << endl; } }; class divCalculator : public AbsCalculator { public: void calculateMethod(double firstNum, double secondNum) { if (secondNum != 0) { cout << firstNum / secondNum << endl; } else { cout << "Divisor cannot be 0." << endl; } } }; class CalculatorFactory // 为什么使用前置声明不行? { public: AbsCalculator* calculator; // 根据不同的方法,“生产”不同的计算器 AbsCalculator* productCalculator(char method) { switch (method) { case '+': calculator = new addCalculator; break; case '-': calculator = new subCalculator; break; case '*': calculator = new multiCalculator; break; case '/': calculator = new divCalculator; break; default: break; } return calculator; // 遗忘返回值 } }; void test() { cout << "Please enter the first number:" << endl; double firstNumber; cin >> firstNumber; cout << "Please enter the Second number:" << endl; double secondNumber; cin >> secondNumber; cout << "Please select calculation method: '+ - * / '" << endl; char method; cin >> method; AbsCalculator* calculator; CalculatorFactory calFactory; calculator = calFactory.productCalculator(method); calculator->setFirstNum(firstNumber); calculator->setSecondNum(secondNumber); calculator->calculateMethod(calculator->getFirstNum(), calculator->getSecondNum()); } int main() { int i = 0; while (i < 5) { test(); i++; } system("pause"); return 0; }
通过输入不同的运算符号,工厂类就能产生不同类型的计算器,就像工厂根据不同的生产订单来生产产品。
但是我也遇到一些问题,比如将工厂类定义在最初的位置,使用前置声明。仍然告诉我:[c2027] 使用了未定义类型。
参考资料:《大话设计模式》,作者:程杰



