最近面试的时候被问到了设计模型-工厂模式,虽然是老掉牙的问题了,但又回头翻了翻书,温故知新吧!
就像学了C++中类的基础知识就应该让自己习惯写出一个“较好”的类来:设计一个较好的类,会通过类来管理资源,即RAII(Resource Acquisition Is Initialization)原则,考虑类的复制构造函数,重载赋值=操作符等,会考虑C++中的内存管理、防止内存泄漏等问题。那么好了,设计好一个类,然后呢?我们的程序需要组合多个类,这些类需要协调工作才能完美地解决问题!
OO(Object-Oriented)设计模式就是针对一些经典场景下,解决面向对象程序设计特定问题的类间关系的设计模板!
通过类之间的关系(继承、组合、聚合、依赖),以体现OO的优势,使得程序的设计满足开放-封闭的原则(对扩展开放接口,对修改封闭:即不希望对程序做大的改动)
一下代码与类图参考文献[1]程杰. 大话设计模式[M]. 清华大学出版社, 2007.
复习基本的UML图:
概念:
- 继承
- 组合(对象同生命周期,具体在类中怎写?)
- 聚合(对象不同生命周期,二者的创建与销毁独立)(组合和聚合应该是用类嵌套(对象成员)与类指针成员的方式实现)
- 依赖(仅仅是一个类的对象会使用另外一个类对象的方法,二者连嵌套关系都没有)
下面针对简单工厂模式、工厂模式、抽象工厂模式,以OO的思想写一些实现计算器的类,通过OO的三大特性:封装、继承、多态,降低程序的耦合度,用设计模式的模板方法使得写出来的代码易于修改(扩充)、复用!
题目:利用面向对象语言实现一个计算器控制台程序,要求输入两个数及运算符,输出运算结果!
计算器版本1:
// calculator1.cpp : 定义控制台应用程序的入口点。
//
//最Low版本的计算器实现两个数相加!
#include "stdafx.h"
#include<iostream>
using namespace std;
int _tmain(int argc, _TCHAR* argv[])
{
double A, B, result;
char op;
cout << "请输入数字A,按回车键确认输入:" << endl;
cin >> A;
try{
if (cin.fail())
throw 1;
}
catch (int)
{
cin.clear();
cin.sync();
cout << "输入错误" << endl;
}
cout << "请输入运算符(+,-,*,/),按回车键确认输入:" << endl;
cin >> op;
cout << "请输入数字B,,按回车键确认输入:" << endl;
cin >> B;
if (op == '+')
result = A + B;
if (op == '-')
result = A - B;
if (op == '*')
result = A*B;
if (op == '/')
result = A / B;
cout << A << op << B << "=" << result << endl;
/*
请输入数字A,按回车键确认输入:
1
请输入运算符(+,-,*,/),按回车键确认输入:
/
请输入数字B,,按回车键确认输入:
0
1/0=1.#INF
请按任意键继续. . .
*/
system("pause");
return 0;
}
计算器版本2:
// calculator2.cpp : 定义控制台应用程序的入口点。
//计算器版本2
#include "stdafx.h"
#include<iostream>
using namespace std;
int _tmain(int argc, _TCHAR* argv[])
{
double NumberA, NumberB, result;
char op;
while (1)
{
cout << "请输入数字A,按回车键确认输入:" << endl;
cin >> NumberA;
try{
if (cin.fail())
throw 1;
}
catch (int)
{
cin.clear();
cin.sync();
cout << "输入错误,请重新输入:" << endl;
continue;
}
break;
}
while (1)
{
cout << "请输入运算符(+,-,*,/),按回车键确认输入:" << endl;
cin >> op;
try
{
if (cin.fail())
throw 1;
}
catch (int)
{
cin.clear();
cin.sync();
cout << "输入错误,请重新输入:" << endl;
continue;
}
break;
}
while (1)
{
cout << "请输入数字B,按回车键确认输入:" << endl;
cin >> NumberB;
try{
if (cin.fail())
throw 1;
}
catch (int)
{
cin.clear();
cin.sync();
cout << "输入错误,请重新输入:" << endl;
continue;
}
break;
}
try{
switch (op)
{
case'+':
result = NumberA + NumberB;
break;
case'-':
result = NumberA - NumberB;
break;
case'*':
result = NumberA*NumberA;
break;
case'/':
if (NumberB == 0)
{
throw 1;
}
else
{
result = NumberA / NumberB;
}
break;
default:
;
}
cout << NumberA<<op<<NumberB<<"=" << result << endl;
}
catch (int )
{
cout << "除数不能为零!" << endl;
//exit(1);
}
system("pause");
return 0;
}
上面的版本只实现了加法和减法,要求程序可扩展,以后能实现对乘法、除法、幂次方、取余数等的功能扩展。
1.简单工厂模式
// SimpleFactory2.cpp : 定义控制台应用程序的入口点。
//
#include "stdafx.h"
#include<iostream>
using namespace std;
class Operation
{
private:
double NumberA;
double NumberB;
public:
virtual double getResult() = 0;/*这里必须是纯虚函数!!(纯虚函数与抽象类!)*/
void setNumberA(double a)
{
NumberA = a;
}
void setNumberB(double b)
{
NumberB = b;
}
double getNumberA()
{
return NumberA;
}
double getNumberB()
{
return NumberB;
}
};
class OperationAdd :public Operation
{
public:
double getResult()/*不同的Operation子类具体实现纯虚函数getReuslt()这个接口!*/
{
return getNumberA() + getNumberB();
}
};
class OperationSub :public Operation
{
public:
double getResult()
{
return getNumberA() - getNumberB();
}
};
class SimpleFactory
{
private:
Operation* oper = nullptr;
public:
Operation* creationOperation(char op)
{
switch (op)
{
case '+':
oper = new OperationAdd();
break;
case '-':
oper = new OperationSub();
break;
default:
;
}
return oper;//oper是指向堆对象的指针,不是栈对象,所有可以返回!
}
};
int _tmain(int argc, _TCHAR* argv[])
{
/*计算器类的客户端*/
Operation* oper;/*多态的实现,基类指针指向不同类型的子类!在调用方法是是调用子类的方法!*/
SimpleFactory simpleFacory;
oper = simpleFacory.creationOperation('+');
oper->setNumberA(1);
oper->setNumberB(2);
double result = oper->getResult();
cout << "result=" << result << endl;
getchar();
return 0;
}
2.工厂模式
// Factory.cpp : 定义控制台应用程序的入口点。
//
#include "stdafx.h"
#include<iostream>
using namespace std;
class Operation
{
private:
double NumberA;
double NumberB;
public:
virtual double getResult() = 0;/*这里必须是纯虚函数!!(纯虚函数与抽象类!)*/
void setNumberA(double a)
{
NumberA = a;
}
void setNumberB(double b)
{
NumberB = b;
}
double getNumberA()
{
return NumberA;
}
double getNumberB()
{
return NumberB;
}
};
class OperationAdd :public Operation
{
public:
double getResult()/*不同的Operation子类具体实现纯虚函数getReuslt()这个接口!*/
{
return getNumberA() + getNumberB();
}
};
class OperationSub :public Operation
{
public:
double getResult()
{
return getNumberA() - getNumberB();
}
};
class IFactory
{
public:
virtual Operation* CreateOperation() = 0;
};
class AddFactory :public IFactory
{
public:
Operation* CreateOperation()
{
return new OperationAdd();
}
};
class SubFactory :public IFactory
{
public:
Operation* CreateOperation()
{
return new OperationSub();
}
};
int _tmain(int argc, _TCHAR* argv[])
{
IFactory* operationFactory = new AddFactory();
Operation* oper = operationFactory->CreateOperation();
oper->setNumberA(1);
oper->setNumberB(2);
double result = oper->getResult();
cout << "retult=" << result << endl;
getchar();
return 0;
}
2.工厂方法
工厂方法(Factory Method):定义一个用于创建对象的接口,让子类决定实例化哪一个类。工厂方法使得一个类的实例化延迟到其子类。
工厂方法设计模式实现时,客户端需要决定实例化哪一个工厂类来实现运算类,选择判断的问题依然存在,只不过是从简单工厂里的内部逻辑判断(switch语句)移到了客户端代码来进行。要想加运行类的具体产品,本来是要修改工厂类的,现在是修改客户端!
面向对象OO,设计模式