工厂模式种类
工厂模式的实现方式可分别简单工厂模式、工厂方法模式、抽象工厂模式
此文重点讲最优的工厂方法。
单工厂模式
特点
工厂类封装了创建具体产品对象的函数。
缺陷
扩展性非常差,新增产品的时候,需要去修改工厂类。
工厂方法模式
UML
特点
1.工厂方法模式抽象出了工厂类,提供创建具体产品的接口,交由子类去实现。
2.工厂方法模式的应用并不只是为了封装具体产品对象的创建,而是要把具体产品对象的创建放到具体工厂类实现。
缺陷
1.每新增一个产品,就需要增加一个对应的产品的具体工厂类。相比简单工厂模式而言,工厂方法模式需要更多的类定义。
2.一条生产线只能一个产品。
抽象工厂模式
UML
特点
提供一个接口,可以创建多个产品族中的产品对象。如创建耐克工厂,则可以创建耐克鞋子产品、衣服产品、裤子产品等。
缺陷
同工厂方法模式一样,新增产品时,都需要增加一个对应的产品的具体工厂类。
三个工厂总结
1.简单工厂模式,,需要去修改工厂类,这违背了开闭法则。
2.工厂方式模式和抽象工厂模式,都需要增加一个对应的产品的具体工厂类,这就会增大了代码的编写量。
学到的工厂方式模式nb封装方法
IFactor.h
#ifndef IFACTOR_H
#define IFACTOR_H
#include <map>
#include <string>
// 抽象产品工具类
template<class AbstractProduct>
class AbstractProductTool
{
public:
virtual AbstractProduct* creatProduct() = 0;
protected:
AbstractProductTool(){}
~AbstractProductTool(){}
};
// 工厂模板类。所有 AbstractProduct 的继承者们对象都用此来创建; AbstractProduct 抽象产品类型的接口如“战斗机”
template<class AbstractProduct>
class ProductFactory
{
public:
static ProductFactory<AbstractProduct> &instance() {
static ProductFactory<AbstractProduct> factory;
return factory;
}
void registerProduct(const std::string &name, AbstractProductTool<AbstractProduct>* adsProductTool) {
m_registerProductMap[name] = adsProductTool;
}
AbstractProduct* createProduct(const std::string &name) {
if (m_registerProductMap.find(name) != m_registerProductMap.end())
return m_registerProductMap[name]->creatProduct();
else
return nullptr;
}
private:
ProductFactory(){}
ProductFactory(const ProductFactory&){}
ProductFactory& operator=(const ProductFactory&){}
std::map<std::string, AbstractProductTool<AbstractProduct>* > m_registerProductMap;
};
// 具体产品工具类,实例化时会将工厂对象注册进 单例的factory; AbstractProduct 相当于工厂的类型如“战斗机”, ConcreteProduct 继承接口的具体产品类如“F22”
template<class AbstractProduct, class ConcreteProduct>
class ConcreteProductTool :public AbstractProductTool<AbstractProduct>
{
public:
explicit ConcreteProductTool(const std::string& name) {
ProductFactory<AbstractProduct>::instance().registerProduct(name, this);
}
AbstractProduct* creatProduct() override {
return new ConcreteProduct();
}
};
// 利用全局静态变量的初始化特性实现产品类的自注册
#define RegisterProduct(AbstractProduct, ConcreteProduct) \
static ConcreteProductTool<AbstractProduct, ConcreteProduct> register##ConcreteProduct(#ConcreteProduct);
#endif // IFACTOR_H
IFighter.h
#ifndef IFIGHTER_H
#define IFIGHTER_H
class Fighter
{
protected:
Fighter(){}
virtual ~Fighter(){}
public:
virtual void fly() = 0;
};
#endif // IFIGHTER_H
ITank.h
#ifndef ITANK_H
#define ITANK_H
class Tank
{
protected:
Tank(){}
virtual ~Tank(){}
public:
virtual void fire() = 0;
};
#endif // ITANK_H
main.cpp
#include <iostream>
#include "./inc/IFactor.h"
#include "TianQi.h"
#include "GuangLing.h"
#include "F22.h"
#include "Jian20.h"
using namespace std;
#define sticky(x) hello##x//合并操作符##将出现在其左右的字符序列合并成一个新的标识符
#define str(y) #y//将传入的参数变为字符串,字符串化
// 将“F22” 这个战斗机类型注册进工厂
RegisterProduct(Fighter, F22);
RegisterProduct(Fighter, Jian20);
// 将 RegisterProduct 宏展开,其实就是实例化模板类 ConcreteProductTool
static ConcreteProductTool<Tank, TianQi> registerConcreteProduct("TianQi");
RegisterProduct(Tank, GuangLing);
int main()
{
// 宏定义解释
int helloWorld = 10;
cout<< sticky(World) <<endl; // 将hello和World链接形成helloWorld ,helloWorld 是一个变量
cout<< str(hello) <<endl; // 将helloWorld 变为字符串
// Fighter 工厂单例,然后生产 F22 战机
Fighter *USAFighter_1 = ProductFactory<Fighter>::instance().createProduct("F22");
USAFighter_1->fly();
Fighter *ChinaFighter_1 = ProductFactory<Fighter>::instance().createProduct("Jian20");
ChinaFighter_1->fly();
// Tank 工厂单例,然后生产 TianQi 坦克
Tank *ChinaTank_1 = ProductFactory<Tank>::instance().createProduct("TianQi");
ChinaTank_1->fire();
Tank *USATank_1 = ProductFactory<Tank>::instance().createProduct("GuangLing");
USATank_1->fire();
return 0;
}
“TianQi.h”\ “GuangLing.h”“F22.h”\ "Jian20.h“ 与其CPP已省略。
程序输出:
10
hello
fast!
faster!
peng peng peng
zhi zhi zhi
总结
如最后的代码所示,我都有 “TianQi.h”\ “GuangLing.h”“F22.h”\ "Jian20.h“ 四个头文件了。我直接new对象不就行了。为何非得用工厂?
其实:上述只是介绍工厂模式,代码不是很贴合。
工厂模式目的:
(1)解耦:把对象的创建和使用的过程分开
(2)降低代码重复:如果创建某个对象的过程都很复杂,需要一定的代码量,而且很多地方都要用到,那么就会有很多的重复代码。
(3)降低维护成本:由于创建过程都由工厂统一管理,所以发生业务逻辑变化,不需要找到所有需要创建某个对象的地方去逐个修正,只需要在工厂里修改即可,降低维护成本。
使用场景:
- 对象的创建过程/实例化准备工作很复杂,需要初始化很多参数、查询数据库等。
2.类本身有好多子类,这些类的创建过程在业务中容易发生改变,或者对类的调用容易发生改变。