以前看设计模式,一直没怎么看懂,现在看了,懂了点皮毛,记录下来,方便自己以后不断改进。
先看一个简单的例子,一个小学生刚刚接触算术,开始学习整数加减法,请你帮他设计一个加减法运算器,你会怎么解决?
#include<stdio.h>
int main()
{
int a,b;
char operation;
int result;
scanf("%d%c%d",&a,&operation,&b);
switch(operation)
{
case '+':
result=a+b;
break;
case '-':
result=a-b;
break;
}
printf("result=%d\n",result);
return 0;
}
既然是设计模式,面向对象的设计思想,这种面向过程的解决方案,我们就不要写了。
我们可以定义一个抽象类Operation,定义两个数据成员和得到这两个数据成员的函数,还有一个纯虚函数GetResult(C++没有interface和abstract class的明显关键字,只能通过纯虚函数去定义接口和关键字)
class Operation
{
public:
Operation(int numA,int numB)
{
numberA=numA;
numberB=numB;
}
int GetNumberA()
{
return numberA;
}
int GetNumberB()
{
return numberB;
}
virtual int GetResult()=0; //让子类去实现这个纯虚函数,不同的运算符实现不同的操作结果
private:
int numberA;
int numberB;
};
然后加法类和减法类继承这个Operation类
//加法类
class OperationAdd:public Operation
{
public:
OperationAdd(int numA,int numB):Operation(numA,numB){}
int GetResult()
{
int result=GetNumberA()+GetNumberB();
return result;
}
};
//减法类
class OperationSub:public Operation
{
public:
OperationSub(int numA,int numB):Operation(numA,numB){}
int GetResult()
{
int result=GetNumberA()-GetNumberB();
return result;
}
};
这个时候,我们在客户端进行调用,会怎么做
int main()
{
Operation* operation=new OperationAdd(1,2);
cout<<operation->GetResult()<<endl;
}
也就是说,我们知道接口和具体的实现类(加法类或者减法类)。如果我们只知道,而不知道具体的实现类呢。我们该怎么办。解决这个问题,就用到了简单工厂模式,我们可以创建一个工厂类,在工厂类里有一个创建接口的成员函数
//私有化构造函数,把工厂类做成工厂工具类,防止无谓的创建简单工厂实例
class OperationFactory
{
private:
OperationFactory(){}
public:
static Operation* CreateOperation(int numA,int numB,char operate)
{
Operation* oper=NULL;
if(operate=='+')
oper=new OperationAdd(numA,numB);
else if(operate=='-')
oper=new OperationSub(numA,numB);
return oper;
}
};
现在,我们在客户端进行调用
int main()
{
Operation* operation=OperationFactory::CreateOperation(1,2,'+');
cout<<operation->GetResult()<<endl;
}
这个时候,我们只需要知道接口Operation即可,而无需知道具体的实现类。这样,我们就将具体的实现类隔离起来了。你可能话说,那不就是把加法类和减法类的创建过程移植到了工厂里面了,是的,理解简单工厂方法模式,关键在于理解工厂类的位置。
代码实现如下
#include<iostream>
#include<string>
using namespace std;
class Api
{
public:
virtual void Operation(string s)=0;
};
class ImpA:public Api
{
public:
void Operation(string s) { cout<<"ImpA::"<<s<<endl; }
};
class ImpB:public Api
{
public:
void Operation(string s) { cout<<"ImpB::"<<s<<endl; }
};
class Factory
{
private:
Factory(){}
public:
static Api* CreateApi(int condition){
Api* api=NULL;
switch (condition)
{
case 1:
api=new ImpA();
break;
case 2:
api=new ImpB();
break;
default:
api=NULL;
}
return api;
}
};
int main()
{
Api* api=Factory::CreateApi(2);
api->Operation("helloworld");
delete api;
}
工厂类介意客户端和内部实现之间,起到了桥梁的作用,隐藏了内部的实现。
当然,因为CreateApi是通过了判断条件来选择创建具体的类,这在一定程度上也暴露了内在的实现。简单工厂模式的实质就是选择实现。通过简单工厂,可以实现客户端和具体类的解耦,客户端根本就不知道到底是由谁来实现的,也就不知道具体是如何实现的,客户端只是通过工厂来获取它需要的接口对象。
小学生学习完了加减法之后,开始学习乘法了,这时候我们应该怎么做呢?你可能会说,继承Operation,新建一个新的OperationMul类,然后在简单工厂类里面加一个判断条件不就行了?添加一个新的OperationMul类没有问题,但是修改简单工厂类就不好了,因为这样就违反了“开放——封闭原则”,“开放—封闭”,是说软件实体(类、模块、函数等)可以进行扩展,但是不可修改。对于扩展是开放,对于更改是封闭的。
解决这个问题就需要用到另一个模式,工厂方法模式!