1. 简介
简单工厂模式又称静态工厂方法模式,属于创建型模式。简单工厂模式是由一个工厂对象决定创建出哪一种产品类的实例。简单的工厂模式是工厂模式中最简单实用的模式,但是它不属于23中GOF设计模式。简单的工厂模式其实就是工厂方法模式的一种特例,两者归为一类。
在简单工厂模式中,可以根据参数的不同返回不同类的实例。简单的工厂模式专门定义一个类来负责创建其他类的实例,被创建的实例通常都具有共同的父类。
我们先来看看它的组成:
- 工厂角色:这是本模式的核心,它负责实现创建所有实例的内部逻辑。工厂类的创建产品类的方法可以被外界直接调用,进而创建所需的产品对象。
- 抽象产品角色:简单工厂模式所创建的所有对象的父类,它负责描述所有实例的公共接口。
- 具体产品角色:是简单工厂模式的创建目标,所有创建的对象都是充当这个角色的某个具体类的实例。
下面我们用类图(UML)来表示三者的关系:
2. 简单工厂模式案例分析
现在我们来考虑一个简单的软件应用场景:比方说现在我们正在开发某个企业级加密系统,该系统有个不可或缺的功能——文档加密。在国内我们比较常见的加密算法有:IDEA 算法、RSA算法、AES算法等。考虑到实际的应用,我们的加密功能需要支持现阶段主流的加密算法。当然,我们还得考虑到未来(可能出现的更为出色的加密算法)。为此,我们还需要考虑到扩展性。
此时,我们就可以考虑用简单的工厂模式来实现该功能了。整个功能的实现上的思路如下:我们提供一个工厂类,该工厂类职能便是通过某个参数,生产出对应的算法类——这就是工厂角色;我们还提供一个通用的算法抽象基类,该基类抽象出加密的接口——这就是抽象产品角色;最后,我们还在基类的基础上派生出各种加密算法——这就是具体的产品角色。
下面就是具体的C++代码:
抽象产品角色:
/*********************************************************************************
*Copyright(C),Your Company
*FileName: ArithmeticProduct.h
*Author: Huangjh
*Version:
*Date: 2017-10-11
*Description: 用于描述加密算法的抽象基类,该类包含一个用于加密算法的纯虚函数
*Others:
*Function List:
*History:
1.Date:
Author:
Modification:
2.…………
**********************************************************************************/
#ifndef _ARITHMETIC_PRODUCT_H
#define _ARITHMETIC_PRODUCT_H
#include <string>
class CArithmeticProduct
{
public:
CArithmeticProduct() { }
~CArithmeticProduct() { }
virtual void encryption(std::string strFileName) = 0;
};
#endif //#ifndef _ARITHMETIC_PRODUCT_H
具体产品角色——RSA:
/*********************************************************************************
*Copyright(C),Your Company
*FileName: ArithmeticRSA.h
*Author: Huangjh
*Version:
*Date: 2017-10-11
*Description: 具体的产品类——RSA加密算法
*Others:
*Function List:
*History:
1.Date:
Author:
Modification:
2.…………
**********************************************************************************/
#ifndef _ARITHMETIC_RSA_H
#define _ARITHMETIC_RSA_H
#include <iostream>
#include <string>
#include "ArithmeticProduct.h"
class CArithmeticRSA : public CArithmeticProduct
{
public:
CArithmeticRSA() { }
~CArithmeticRSA() { }
void encryption(std::string strFileName)
{
std::cout << "文件:" << strFileName << "进行RSA加密" << std::endl;
}
};
#endif //#ifndef _ARITHMETIC_RSA_H
具体产品角色——IDEA:
/*********************************************************************************
*Copyright(C),Your Company
*FileName: ArithmeticIDEA.h
*Author: Huangjh
*Version:
*Date: 2017-10-11
*Description: 具体的产品类——IDEA加密算法
*Others:
*Function List:
*History:
1.Date:
Author:
Modification:
2.…………
**********************************************************************************/
#ifndef _ARITHMETIC_IDEA_H
#define _ARITHMETIC_IDEA_H
#include <iostream>
#include <string>
#include "ArithmeticProduct.h"
class CArithmeticIDEA : public CArithmeticProduct
{
public:
CArithmeticIDEA() { }
~CArithmeticIDEA() { }
void encryption(std::string strFileName)
{
std::cout << "文件:" << strFileName << "进行IDEA加密" << std::endl;
}
};
#endif //#ifndef _ARITHMETIC_IDEA_H
具体产品角色——AES:
/*********************************************************************************
*Copyright(C),Your Company
*FileName: ArithmeticAES.h
*Author: Huangjh
*Version:
*Date: 2017-10-11
*Description: 具体的产品类——AES加密算法
*Others:
*Function List:
*History:
1.Date:
Author:
Modification:
2.…………
**********************************************************************************/
#ifndef _ARITHMETIC_AES_H
#define _ARITHMETIC_AES_H
#include <iostream>
#include <string>
#include "ArithmeticProduct.h"
class CArithmeticAES : public CArithmeticProduct
{
public:
CArithmeticAES() { }
~CArithmeticAES() { }
void encryption(std::string strFileName)
{
std::cout << "文件:" << strFileName << "进行AES加密" << std::endl;
}
};
#endif //#ifndef _ARITHMETIC_AES_H
工厂角色:
/*********************************************************************************
*Copyright(C),Your Company
*FileName: ArithmeticFactory.h
*Author: Huangjh
*Version:
*Date: 2017-10-11
*Description: 工厂类——加密算法的工厂类
*Others:
*Function List:
*History:
1.Date:
Author:
Modification:
2.…………
**********************************************************************************/
#ifndef _ARITHMETIC_FACTORY_H
#define _ARITHMETIC_FACTORY_H
#include <new>
#include "ArithmeticRSA.h"
#include "ArithmeticIDEA.h"
#include "ArithmeticAES.h"
class CArithmeticFactory
{
public:
CArithmeticFactory() { }
~CArithmeticFactory() { }
//这就是用于生产具体加密算法的工厂类,只需要传入算法名称即可,
//如后续需要添加算法,只需要编写具体的算法类和修改该方法即可
static CArithmeticProduct *createArithmetic(std::string strArithmetic)
{
try
{
CArithmeticProduct *pArithmetic = NULL;
if (strArithmetic == "RSA")
pArithmetic = new CArithmeticRSA();
else if (strArithmetic == "IDEA")
pArithmetic = new CArithmeticIDEA();
else if (strArithmetic == "AES")
pArithmetic = new CArithmeticAES();
else
pArithmetic = NULL;
return pArithmetic;
}
catch (std::bad_alloc &ex)
{
std::cout << "throw exception:" << ex.what() << std::endl;
abort();
}
}
};
#endif //#ifndef _ARITHMETIC_FACTORY_H
测试程序:
/*********************************************************************************
*Copyright(C),Your Company
*FileName: ArithmeticMain.cpp
*Author: Huangjh
*Version:
*Date: 2017-10-11
*Description: 简单工厂模式的测试程序
*Others:
*Function List:
*History:
1.Date:
Author:
Modification:
2.…………
**********************************************************************************/
#include "ArithmeticFactory.h"
int main(void)
{
CArithmeticProduct *pEncryptionArithmetic = CArithmeticFactory::createArithmetic("AES");
pEncryptionArithmetic->encryption("huangjh.txt");
delete pEncryptionArithmetic;
return 0;
}
运行结果如下:
文件:huangjh.txt进行AES加密
对应简单的UML图如下:
3.简单工厂模式的优缺点
3.1 简单工厂模式的优点
- 工厂类含有必要的判断逻辑,可以决定在什么时候创建哪一个产品类的实例,客户端可以免除直接创建产品对象的责任,而仅仅“消费”产品;简单工厂模式通过这种做法实现了对责任的分割,它提供了专门的工厂类用于创建对象。明确了各自的职责和权利,有利于整个软件体系结构的优化。
3.2 简单工厂模式的缺点
- 由于工厂类集中了所有实例的创建逻辑,违反了高内聚责任分配原则,将全部创建逻辑集中到了一个工厂类中;它所能创建的类只能是事先考虑到的,如果需要添加新的类,则需要改变工厂类了。
- 当系统中的具体产品类不断增多时候,可能会出现要求工厂类根据不同条件创建不同实例的需求。这种对条件的判断和对具体产品类型的判断交错在一起,很难避免模块功能的蔓延,对系统的维护和扩展非常不利。
4. 简单工厂模式的适用场景
当我们遇到以下情况时可以使用简单的工厂模式:
- 工厂类负责创建的对象比较少:由于创建的对象较少,不会造成工厂方法中的业务逻辑太过复杂。
- 客户端只知道传入工厂类的参数,对于如何创建对象不关心:客户端既不需要关心创建细节,甚至连类名都不需要记住,只需要知道类型所对应的参数。