引入:利用C++、Java、C#或VB.NET任意一种面向对象语言实现一个计算器控制程序,要求输入两个数和运算符号,得到结果。
一、最粗糙实现版本(Calculator01):
#include<iostream>
#include<string>
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<iostream>
#include<string>
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):
将业务逻辑与界面逻辑分开,降低之间的耦合度。将计算器类进行封装。
#include<iostream>
using 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):
#include<iostream>
using 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<iostream>
#include<string>
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] 使用了未定义类型。
参考资料:《大话设计模式》,作者:程杰