0. 简介
继单例模式写完后,我觉得对于C++的高级用法可以来开一个专栏来专门整理与阐述,这里,我将以我们最常用的工厂模式开始,来逐步的共同学习。
1. 初级工厂模式
工厂顾名思义就是创建产品,根据产品是具体产品还是具体工厂可分为简单工厂模式和工厂方法模式,根据工厂的抽象程度可分为工厂方法模式和抽象工厂模式。本节从一个具体的例子逐步深入分析,来体会三种工厂模式的应用场景和利弊。这里借用网络上的例子来结合自己的理解来解释。
1.1 简单工厂模式
简单工厂模式对对象创建管理方式最为简单,因为其仅仅简单的对不同类对象的创建进行了一层薄薄的封装。该模式通过向工厂传递类型来指定要创建的对象,其UML类图如下:
结构组成:
工厂类(ShoesFactory
):工厂模式的核心类,会定义一个用于创建指定的具体实例对象的接口。
抽象产品类(Shoes
):是具体产品类的继承的父类或实现的接口。
具体产品类(NiKeShoes\AdidasShoes\LiNingShoes
):工厂类所创建的对象就是此具体产品实例。
优点与不足:
优点: 结构简单,管理方式简单
缺点: 扩展性非常差,新增产品的时候,需要去修改工厂类。
抽象产品类,用于存放一类特征相似的实现,并用于定义具体产品类
// 鞋子抽象类
class Shoes
{
public:
virtual ~Shoes() {}
virtual void Show() = 0;
};
// 耐克鞋子
class NiKeShoes : public Shoes
{
public:
void Show()
{
std::cout << "我是耐克球鞋,我的广告语:Just do it" << std::endl;
}
};
// 阿迪达斯鞋子
class AdidasShoes : public Shoes
{
public:
void Show()
{
std::cout << "我是阿迪达斯球鞋,我的广告语:Impossible is nothing" << std::endl;
}
};
工厂类用于统计所有的特征,可以根据enum
类型创建具体的产品对象。
enum SHOES_TYPE
{
NIKE,
ADIDAS
};
// 总鞋厂
class ShoesFactory
{
public:
// 根据鞋子类型创建对应的鞋子对象
Shoes *CreateShoes(SHOES_TYPE type)
{
switch (type)
{
case NIKE:
return new NiKeShoes();
break;
case ADIDAS:
return new AdidasShoes();
break;
default:
return NULL;
break;
}
}
};
主函数,先是构造了工厂对象,后创建指定类型的具体产品对象,并实现内部的操作。
int main()
{
ShoesFactory shoesFactory;
// 从鞋工厂对象创建耐克鞋对象
Shoes *pNikeShoes = shoesFactory.CreateShoes(NIKE);
if (pNikeShoes != NULL)
{
// 耐克球鞋广告喊起
pNikeShoes->Show();
// 释放资源
delete pNikeShoes;
pNikeShoes = NULL;
}
// 从鞋工厂对象创建阿迪达斯鞋对象
Shoes *pAdidasShoes = shoesFactory.CreateShoes(ADIDAS)
if (pAdidasShoes != NULL)
{
// 阿里达斯球鞋广告喊起
pAdidasShoes->Show();
// 释放资源
delete pLiNingShoes;
pAdidasShoes = NULL;
}
return 0;
}
1.2 工厂方法模式
和简单工厂模式中工厂负责生产所有产品相比,工厂方法模式将生成具体产品的任务分发给具体的产品工厂,其UML类图如下:
结构组成:
抽象工厂类厂(ShoesFactory
):工厂方法模式的核心类,提供创建具体产品的接口,由具体工厂类实现。
具体工厂类(NiKeProducer\AdidasProducer\LiNingProducer
):继承于抽象工厂,实现创建对应具体产品对象的方式。
抽象产品类(Shoes
):它是具体产品继承的父类(基类)。
具体产品类(NiKeShoes\AdidasShoes\LiNingShoes
):具体工厂所创建的对象,就是此类。
优点与不足:
优点: 工厂方法模式抽象出了工厂类,并把具体产品对象的创建放到具体工厂类实现。实现了一个工厂生产一类产品,不需要修改工厂类,只需要增加新的具体工厂类即可。
缺点: 每新增一个产品,就需要增加一个对应的产品的具体工厂类。相比简单工厂模式而言,工厂方法模式需要更多的类定义。
抽象工厂类,提供了创建具体工厂类的纯虚函数,并通过具体工厂类来返回具体产品类
// 总鞋厂
class ShoesFactory
{
public:
virtual Shoes *CreateShoes() = 0;
virtual ~ShoesFactory() {}
};
// 耐克生产者/生产链
class NiKeProducer : public ShoesFactory
{
public:
Shoes *CreateShoes()
{
return new NiKeShoes();
}
};
// 阿迪达斯生产者/生产链
class AdidasProducer : public ShoesFactory
{
public:
Shoes *CreateShoes()
{
return new AdidasShoes();
}
};
抽象产品类同上
// 同上
主函数函数针对每种类型的具体产品,构造了每种具体产品的具体工厂,再由每个具体工厂生产出对应的产品。
int main()
{
// ================ 生产耐克流程 ==================== //
// 鞋厂开设耐克生产线
ShoesFactory *niKeProducer = new NiKeProducer();
// 耐克生产线产出球鞋
Shoes *nikeShoes = niKeProducer->CreateShoes();
// 耐克球鞋广告喊起
nikeShoes->Show();
// 释放资源
delete nikeShoes;
delete niKeProducer;
// ================ 生产阿迪达斯流程 ==================== //
// 鞋厂开设阿迪达斯生产者
ShoesFactory *adidasProducer = new AdidasProducer();
// 阿迪达斯生产线产出球鞋
Shoes *adidasShoes = adidasProducer->CreateShoes();
// 阿迪达斯球鞋广喊起
adidasShoes->Show();
// 释放资源
delete adidasShoes;
delete adidasProducer;
return 0;
}
1.3 抽象工厂模式
上面两种模式不管工厂怎么拆分抽象,都只是针对一类产品,如果需要多种产品,那就需要使用抽象工厂模式。抽象工厂模式通过在AbstarctFactory中增加创建产品的接口,并在具体子工厂中实现新加产品的创建,当然前提是子工厂支持生产该产品。否则继承的这个接口可以什么也不干。
结构组成(和工厂方法模式一样):
抽象工厂类厂(ShoesFactory
):工厂方法模式的核心类,提供创建具体产品的接口,由具体工厂类实现。
具体工厂类(NiKeProducer
):继承于抽象工厂,实现创建对应具体产品对象的方式。
抽象产品类(Shoes\Clothe
):它是具体产品继承的父类(基类)。
具体产品类(NiKeShoes\NiKeClothe
):具体工厂所创建的对象,就是此类。
优点与不足:
优点: 提供一个接口,可以创建多个产品族中的产品对象,同一类的多个产品对象不需要创建多个工厂。
缺点: 相比简单工厂模式而言,抽象工厂模式需要更多的类定义。
抽象产品类+具体产品类
// 基类 衣服
class Clothe
{
public:
virtual void Show() = 0;
virtual ~Clothe() {}
};
// 基类 鞋子
class Shoes
{
public:
virtual void Show() = 0;
virtual ~Shoes() {}
};
// 耐克衣服
class NiKeClothe : public Clothe
{
public:
void Show()
{
std::cout << "我是耐克衣服,时尚我最在行!" << std::endl;
}
};
// 耐克鞋子
class NiKeShoes : public Shoes
{
public:
void Show()
{
std::cout << "我是耐克球鞋,让你酷起来!" << std::endl;
}
};
抽象工厂类+具体工厂类
// 总厂
class Factory
{
public:
virtual Shoes *CreateShoes() = 0;
virtual Clothe *CreateClothe() = 0;
virtual ~Factory() {}
};
// 耐克生产者/生产链
class NiKeProducer : public Factory
{
public:
Shoes *CreateShoes()
{
return new NiKeShoes();
}
Clothe *CreateClothe()
{
return new NiKeClothe();
}
};
主函数可以通过调用一个工厂的不同方法类做不同的操作
int main()
{
// ================ 生产耐克流程 ==================== //
// 鞋厂开设耐克生产线
Factory *niKeProducer = new NiKeProducer();
// 耐克生产线产出球鞋
Shoes *nikeShoes = niKeProducer->CreateShoes();
// 耐克生产线产出衣服
Clothe *nikeClothe = niKeProducer->CreateClothe();
// 耐克球鞋广告喊起
nikeShoes->Show();
// 耐克衣服广告喊起
nikeClothe->Show();
// 释放资源
delete nikeShoes;
delete nikeClothe;
delete niKeProducer;
return 0;
}
2. 高级工厂模式
2.1 模板工厂
针对工厂方法模式封装成模板工厂类,那么这样在新增产品时,是不需要新增具体的工厂类,减少了代码的编写量。
// 基类 鞋子
class Shoes
{
public:
virtual void Show() = 0;
virtual ~Shoes() {}
};
// 耐克鞋子
class NiKeShoes : public Shoes
{
public:
void Show()
{
std::cout << "我是耐克球鞋,我的广告语:Just do it" << std::endl;
}
};
// 基类 衣服
class Clothe
{
public:
virtual void Show() = 0;
virtual ~Clothe() {}
};
// 优衣库衣服
class UniqloClothe : public Clothe
{
public:
void Show()
{
std::cout << "我是优衣库衣服,我的广告语:I am Uniqlo" << std::endl;
}
};
AbstractFactory
为抽象模板工厂类,其中模板参数:AbstractProduc_t
产品抽象类,如Shoes、Clothe
ConcreteFactory
为具体模板工厂类,其中模板参数:AbstractProduct_t
产品抽象类(如Shoes、Clothe
),ConcreteProduct_t
产品具体类(如NiKeShoes、UniqloClothe
)
// 抽象模板工厂类
// 模板参数:AbstractProduct_t 产品抽象类
template <class AbstractProduct_t>
class AbstractFactory
{
public:
virtual AbstractProduct_t *CreateProduct() = 0;
virtual ~AbstractFactory() {}
};
// 具体模板工厂类
// 模板参数:AbstractProduct_t 产品抽象类,ConcreteProduct_t 产品具体类
template <class AbstractProduct_t, class ConcreteProduct_t>
class ConcreteFactory : public AbstractFactory<AbstractProduct_t>
{
public:
AbstractProduct_t *CreateProduct()
{
return new ConcreteProduct_t();
}
};
主函数,根据不同类型的产品,构造对应的产品的工厂对象,便可通过对应产品的工厂对象创建具体的产品对象。
int main()
{
// 构造耐克鞋的工厂对象
ConcreteFactory<Shoes, NiKeShoes> nikeFactory;
// 创建耐克鞋对象
Shoes *pNiKeShoes = nikeFactory.CreateProduct();
// 打印耐克鞋广告语
pNiKeShoes->Show();
// 构造优衣库衣服的工厂对象
ConcreteFactory<Clothe, UniqloClothe> uniqloFactory;
// 创建优衣库衣服对象
Clothe *pUniqloClothe = uniqloFactory.CreateProduct();
// 打印优衣库广告语
pUniqloClothe->Show();
// 释放资源
delete pNiKeShoes;
pNiKeShoes = NULL;
delete pUniqloClothe;
pUniqloClothe = NULL;
return 0;
}
2.2 产品注册模板类+单例工厂模板类
模板工厂虽然在新增产品的时候,不需要新增具体的工厂类,但是缺少一个可以统一随时随地获取指定的产品对象的类。产品的注册对象可以用std::map的方式保存,通过key-valve的方式可以轻松简单的获取对应的产品对象实例。
IProductRegistrar
为产品注册抽象类,模板参数 ProductType_t
表示的类是产品抽象类(如Shoes、Clothe
)。提供了产品对象创建的纯虚函数CreateProduct
。
ProductFactory
为工厂模板类,模板参数 ProductType_t
表示的类是产品抽象类(如Shoes、Clothe
)。用于保存注册产品对象到std::map
中和获取对应的产品对象。
ProductRegistrar
为产品注册模板类,模板参数 ProductType_t
表示的类是产品抽象类(如Shoes、Clothe
),ProductImpl_t
表示的类是具体产品(如NikeShoes、UniqloClothe
)。用于注册产品到工厂类和创建产品实例对象。
// 基类,产品注册模板接口类
// 模板参数 ProductType_t 表示的类是产品抽象类
template <class ProductType_t>
class IProductRegistrar
{
public:
// 获取产品对象抽象接口
virtual ProductType_t *CreateProduct() = 0;
protected:
// 禁止外部构造和虚构, 子类的"内部"的其他函数可以调用
IProductRegistrar() {}
virtual ~IProductRegistrar() {}
private:
// 禁止外部拷贝和赋值操作
IProductRegistrar(const IProductRegistrar &);
const IProductRegistrar &operator=(const IProductRegistrar &);
};
// 工厂模板类,用于获取和注册产品对象
// 模板参数 ProductType_t 表示的类是产品抽象类
template <class ProductType_t>
class ProductFactory
{
public:
// 获取工厂单例,工厂的实例是唯一的
static ProductFactory<ProductType_t> &Instance()
{
static ProductFactory<ProductType_t> instance;
return instance;
}
// 产品注册
void RegisterProduct(IProductRegistrar<ProductType_t> *registrar, std::string name)
{
m_ProductRegistry[name] = registrar;
}
// 根据名字name,获取对应具体的产品对象
ProductType_t *GetProduct(std::string name)
{
// 从map找到已经注册过的产品,并返回产品对象
if (m_ProductRegistry.find(name) != m_ProductRegistry.end())
{
return m_ProductRegistry[name]->CreateProduct();
}
// 未注册的产品,则报错未找到
std::cout << "No product found for " << name << std::endl;
return NULL;
}
private:
// 禁止外部构造和虚构
ProductFactory() {}
~ProductFactory() {}
// 禁止外部拷贝和赋值操作
ProductFactory(const ProductFactory &);
const ProductFactory &operator=(const ProductFactory &);
// 保存注册过的产品,key:产品名字 , value:产品类型
std::map<std::string, IProductRegistrar<ProductType_t> *> m_ProductRegistry;
};
// 产品注册模板类,用于创建具体产品和从工厂里注册产品
// 模板参数 ProductType_t 表示的类是产品抽象类(基类),ProductImpl_t 表示的类是具体产品(产品种类的子类)
template <class ProductType_t, class ProductImpl_t>
class ProductRegistrar : public IProductRegistrar<ProductType_t>
{
public:
// 构造函数,用于注册产品到工厂,只能显示调用
explicit ProductRegistrar(std::string name)
{
// 通过工厂单例把产品注册到工厂
ProductFactory<ProductType_t>::Instance().RegisterProduct(this, name);
}
// 创建具体产品对象指针
ProductType_t *CreateProduct()
{
return new ProductImpl_t();
}
};
主函数:
int main()
{
// ========================== 生产耐克球鞋过程 ===========================//
// 注册产品种类为Shoes(基类),产品为NiKe(子类)到工厂,产品名为nike
ProductRegistrar<Shoes, NiKeShoes> nikeShoes("nike");
// 从工厂获取产品种类为Shoes,名称为nike的产品对象
Shoes *pNiKeShoes = ProductFactory<Shoes>::Instance().GetProduct("nike");
// 显示产品的广告语
pNiKeShoes->Show();
// 释放资源
if (pNiKeShoes)
{
delete pNiKeShoes;
}
// ========================== 生产优衣库衣服过程 ===========================//
// 注册产品种类为Clothe(基类),产品为UniqloClothe(子类)到工厂,产品名为uniqlo
ProductRegistrar<Clothe, UniqloClothe> adidasShoes("uniqlo");
// 从工厂获取产品种类为Shoes,名称为adidas的产品对象
Clothe *pUniqloClothe = ProductFactory<Clothe>::Instance().GetProduct("uniqlo");
// 显示产品的广告语
pUniqloClothe->Show();
// 释放资源
if (pUniqloClothe)
{
delete pUniqloClothe;
}
return 0;
}
3. 工厂模式代码模板
学习了上述简单的工厂模式与进阶的工厂模式,这里作者给出一个基于工厂模式的代码模板,该模板中包含有注册,注销,获取状态等操作。同时该代码非常清晰,适合二次开发
#pragma once
#include <map>
#include <functional>
template <class IdentifierType, class ProductType>
class DefaultFactoryError
{
public:
class Exception : public std::exception
{
public:
Exception(const IdentifierType& unkownId)
:unknownId_(unkownId){}
const char* what() const noexcept override
{
return "Unknown object type passed to Factory";
}
const IdentifierType GetId()
{
return unknownId_;
}
private:
IdentifierType unknownId_;
};
protected:
ProductType* OnUnknownType(const IdentifierType& id)
{
throw Exception(id);
}
};
template
<
class AbstractProduct,
class IdentifierType,
class ProductCreator = std::function<AbstractProduct*(void)>,
template<typename, class>
class FactoryErrorPolicy = DefaultFactoryError
>
class Factory
: public FactoryErrorPolicy<IdentifierType, AbstractProduct>
{
public:
bool Register(const IdentifierType& id, ProductCreator functor)
{
return associations_.insert(std::make_pair(id, functor)).second;
}
bool Unregister(const IdentifierType& id)
{
return associations_.erase(id);
}
AbstractProduct* CreateObject(const IdentifierType& id)
{
typename std::map<IdentifierType, ProductCreator>::const_iterator i = associations_.find(id);
if(i != associations_.end())
{
return (i->second)();
}
return this->OnUnknownType(id);
}
private:
std::map<IdentifierType, ProductCreator> associations_;
};
主函数调用,可动态扩展调用方法
#include <iostream>
#include <typeinfo>
#include "factory.h"
class Shap
{
public:
virtual ~Shap() {}
virtual void Rote(const float) = 0;
};
class Box : public Shap
{
public:
void Rote(const float angle)
{
std::cout << angle << std::endl;
}
};
int main(int argc, char **argv)
{
try
{
Factory<Shap, std::string> factory;
std::cout << typeid(Box).name() << std::endl;
// https://blog.csdn.net/qq_35587463/article/details/105054277
// 通过lamba返回一个Shap的类指针,内部为Box类
std::cout << factory.Register(typeid(Box).name(), []() -> Shap * { return new Box; }) << std::endl;
std::cout << factory.Unregister(typeid(Box).name()) << std::endl;
std::cout << factory.CreateObject(typeid(Box).name()) << std::endl;
}
catch (const std::exception &e)
{
std::cout << e.what() << std::endl;
}
return 0;
}
参考链接
https://www.cnblogs.com/hebaichuanyeah/category/824625.html
评论(0)
您还未登录,请登录后发表或查看评论