工厂模式:主要是为创建对象提供过渡接口,以便将创建对象的具体过程屏蔽隔离起来,达到提高灵活性的目的。
工厂模式可分为:
- 简单工厂模式(Simple Factory);
- 工厂方法模式(Factory Method);
- 抽象工厂模式(Abstract Factory)。
这三种模式从上到下逐步抽象,并更具有一般性。
为了更加能体会工厂模式的意义,先举一个简单例子。通常我们在实现一个简单计算器Demo时。
可能编写如下代码:
/* 计算器Demo*/
#include <iostream>
using namespace std;
double Calcium(double numA, double numB, char op){
double result = 0;
switch (op){
case'+':
result = numA + numB;
break;
case'-':
result = numA - numB;
break;
case'*':
result = numA*numB;
break;
case'/':
if (numB == 0){
cout << "不能除以 0 !!!" << endl;
break;
}
result = numA / numB;
break;
default: break;
}
return result;
}
int main(){
cout << Calcium(1, 2, '+') << endl;
return 0;
}
对于我们常用的"+,-,*,/"运算是没有问题的,但是上面实现仅仅能满足当前的需求,代码强耦合,如果调用Calcium出错则直接导致程序崩溃,比如:我们需要开方操作时,我们得添加该操作到方法中,并重新编译整个程序,而在修改时如果将其他分支修改了,也会造成程序错误。所以程序的维护性、扩展性、复用性很差。
简单工厂模式:
简单工厂模式又称静态工厂方法模式。
它主要是定义了一个用于创建对象的接口。

/* 简单工厂模式 */
#include <iostream>
#include <unordered_map>
using namespace std;
unordered_map<string, int>mm { { "+", 1 }, { "-", 2 }, { "*", 3}, { "/", 4 } };
class Operation{
public:
void SetNumberA(double numA){
_numA = numA;
}
void SetNumberB(double numB){
_numB = numB;
}
double GetNumberA(){
return _numA;
}
double GetNumberB(){
return _numB;
}
virtual double GetResult(){
double result = 0;
return result;
}
private:
double _numA;
double _numB;
};
class Add :public Operation{
public:
double GetResult(){
double result = 0;
result = GetNumberA() + GetNumberB();
return result;
}
};
class Sub :public Operation{
public:
double GetResult(){
double result = 0;
result = GetNumberA() - GetNumberB();
return result;
}
};
class Mul :public Operation{
public:
double GetResult(){
double result = 0;
result = GetNumberA() * GetNumberB();
return result;
}
};
class Div :public Operation{
public:
double GetResult(){
double result = 0;
if (GetNumberB() == 0)
throw "不能除以 0 !!!";
result = GetNumberA() / GetNumberB();
return result;
}
};
class OperationFactory{
public:
static Operation* CreateOperate(string operate){
Operation* op = nullptr;
int i = mm[operate];
switch (i)
{
case 1:
op = new Add();
break;
case 2:
op = new Sub();
break;
case 3:
op = new Mul();
break;
case 4:
op = new Div();
break;
default:
break;
}
return op;
}
};
int main()
{
Operation* oper;
oper = OperationFactory::CreateOperate("/");
oper->SetNumberA(12);
oper->SetNumberB(0);
try{
cout << oper->GetResult() << endl;
}
catch (const char* msg){
cout << msg << endl;
}
return 0;
}
在简单工厂模式下,如果我们要对程序操作进行扩展,可以直接写一个类继承Operation类,然后独立编写该类,而不会影响到其他模块。在之后运行中如果出现问题,也能很快排错,仅仅修改错误模块的代码。通过继承Operation类的成员变量、成员方法提高了代码复用性。
此外工厂类中包含了必要的逻辑判断,根据客户端的具体调用动态实例化相关类。对于客户端去除了与具体产品的依赖。
通过比较,简单工厂模式的优点不言而喻。
工厂方法模式:
工厂方法模式,定义一个用于创建对象的接口,让子类决定实例化哪一个类。工厂方法使一个类的实例化延迟到其子类。
通过之前简单工厂我们实现了业务逻辑与显示逻辑的分离,工厂类通过判断客户需求而实例化不同的类。但也导致工厂类与其分支的强耦合,再者我们如果要添加其他操作时,就需要修改工厂类的switch-case语句,而这就违反了开放-封闭原则。可以有依赖倒转原则抽象化工厂类,之后的添加功能只需增加相应工厂类和运算类,修改也只对自己类模块修改。

/* 工厂方法模式 */
#include <iostream>
using namespace std;
class Operation{
public:
void SetNumberA(double numA){
_numA = numA;
}
void SetNumberB(double numB){
_numB = numB;
}
double GetNumberA(){
return _numA;
}
double GetNumberB(){
return _numB;
}
virtual double GetResult(){
double result = 0;
return result;
}
private:
double _numA;
double _numB;
};
class Add :public Operation{
public:
double GetResult(){
double result = 0;
result = GetNumberA() + GetNumberB();
return result;
}
};
class Sub :public Operation{
public:
double GetResult(){
double result = 0;
result = GetNumberA() - GetNumberB();
return result;
}
};
class Mul :public Operation{
public:
double GetResult(){
double result = 0;
result = GetNumberA() * GetNumberB();
return result;
}
};
class Div :public Operation{
public:
double GetResult(){
double result = 0;
if (GetNumberB() == 0)
throw "不能除以 0 !!!";
result = GetNumberA() / GetNumberB();
return result;
}
};
class IFactory{
public:
virtual Operation* CreateFactory() = 0;
};
class AddFactory :public IFactory{
public:
Operation* CreateFactory(){
return new Add();
}
};
class SubFactory :public IFactory{
public:
Operation* CreateFactory(){
return new Sub();
}
};
class MulFactory :public IFactory{
public:
Operation* CreateFactory(){
return new Mul();
}
};
class DivFactory :public IFactory{
public:
Operation* CreateFactory(){
return new Div();
}
};
int main()
{
IFactory* operFactory = new AddFactory();
Operation* oper = operFactory->CreateFactory();
oper->SetNumberA(1);
oper->SetNumberB(2);
try{
cout << oper->GetResult() << endl;
}
catch (const char* msg){
cout << msg << endl;
}
return 0;
}
通过实现工厂方法模式,我们将判断逻辑交给了客户,客户完全根据自己需求去实例化。
使用工厂方法模式情形:
1) 当客户程序不需要知道要使用对象的创建过程。
2) 客户程序使用的对象存在变动的可能,或者根本就不知道使用哪一个具体的对象。
抽象工厂模式:
抽象工厂模式:提供一个创建一系列相关或依赖对象的接口,而无需指定它们具体的类。
接着之前的例子,如果我们再需要添加某种功能?比如:打印正进行的是什么运算。(很鸡肋,但想不到了orz.)。那么我们该怎么办?
有了之前的基础,我们可以再提供一个抽象类接口:Print 。通过此接口来实现具体的不同运算类。再将创建子类实例的抽象方法写到抽象工厂中,之后实现的就是具体的运算工厂。

/* Print接口及其分类 */
class Print{
public:
virtual void PrintStatement() = 0;
};
class AddPrint: public Print{
public:
void PrintStatement(){
cout << "这是加法 !!!" << endl;
}
};
class SubPrint : public Print{
public:
void PrintStatement(){
cout << "这是减法 !!!" << endl;
}
};
class MulPrint : public Print{
public:
void PrintStatement(){
cout << "这是乘法 !!!" << endl;
}
};
class DivPrint : public Print{
public:
void PrintStatement(){
cout << "这是除法 !!!" << endl;
}
};
/* 将该功能添加到我们工厂中 */
class IFactory{
public:
virtual Operation* CreateFactory() = 0;
virtual Print* CreatePrintFactory() = 0;
};
class AddFactory :public IFactory{
public:
Operation* CreateFactory(){
return new Add();
}
Print* CreatePrintFactory(){
return new AddPrint();
}
};
class SubFactory :public IFactory{
public:
Operation* CreateFactory(){
return new Sub();
}
Print* CreatePrintFactory(){
return new SubPrint();
}
};
class MulFactory :public IFactory{
public:
Operation* CreateFactory(){
return new Mul();
}
Print* CreatePrintFactory(){
return new MulPrint();
}
};
class DivFactory :public IFactory{
public:
Operation* CreateFactory(){
return new Div();
}
Print* CreatePrintFactory(){
return new DivPrint();
}
};
/* 客端调用 */
int main()
{
IFactory* operFactory = new AddFactory();
Operation* oper = operFactory->CreateFactory();
oper->SetNumberA(1);
oper->SetNumberB(2);
try{
cout << oper->GetResult() << endl;
}
catch (const char* msg){
cout << msg << endl;
}
Print* prt = operFactory->CreatePrintFactory();
prt->PrintStatement();
return 0;
}
IFactory是一个抽象工厂接口,它包含所有产品创建的抽象方法。
AddFactory、SubFactory...就是具体的工厂,通常就是在运行时刻创建具体工厂的实例,通过具体工厂来创建特定的产品对象,也就是创建不同产品对象,客户端应使用不同具体工厂。
使用条件:
- 系统中有多个产品族,而系统一次只可能消费其中一族产品。
- 同属于同一个产品族的产品一起使用。
本篇参照《大话设计模式》、《深入浅出设计模式》、《设计模式:可复用面向对象软件的基础》相关章节内容。