c++工厂模式

介绍

前文初始篇C++ 深入浅出工厂模式(初始篇),主要阐述了简单工厂模式、工厂方法模式和抽象工厂模式的结构、特点和缺陷等。以上三种方式,在新增产品时,要么修改工厂类,要么需新增具体的工厂类,说明工厂类的封装性还不够好。

本文进阶篇,主要是将工厂类的封装性提高,达到新增产品时,也不需要修改工厂类,不需要新增具体的工厂类。封装性高的工厂类特点是扩展性高、复用性也高。

模板工厂

针对工厂方法模式封装成模板工厂类,那么这样在新增产品时,是不需要新增具体的工厂类,减少了代码的编写量。

UML图:

c++工厂模式_第1张图片

模板工厂代码:

  • ShoesClothe,分别为鞋子和衣服的抽象类(基类)
  • NiKeShoesUniqloClothe,分别为耐克鞋子和优衣库衣服具体产品类。

// 基类 鞋子
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为抽象模板工厂类,其中模板参数:AbstractProduct_t 产品抽象类,如ShoesClothe
  • ConcreteFactory为具体模板工厂类,其中模板参数:AbstractProduct_t 产品抽象类(如ShoesClothe),ConcreteProduct_t 产品具体类(如NiKeShoesUniqloClothe

// 抽象模板工厂类
// 模板参数:AbstractProduct_t 产品抽象类
template
class AbstractFactory
{
public:
    virtual AbstractProduct_t *CreateProduct() = 0;
    virtual ~AbstractFactory() {}
};

// 具体模板工厂类
// 模板参数:AbstractProduct_t 产品抽象类,ConcreteProduct_t 产品具体类
template
class ConcreteFactory : public AbstractFactory
{
public:
    AbstractProduct_t *CreateProduct()
    {
        return new ConcreteProduct_t();
    }
};

  • main函数,根据不同类型的产品,构造对应的产品的工厂对象,便可通过对应产品的工厂对象创建具体的产品对象。

int main()
{
    // 构造耐克鞋的工厂对象
    ConcreteFactory nikeFactory;
    // 创建耐克鞋对象
    Shoes *pNiKeShoes = nikeFactory.CreateProduct();
    // 打印耐克鞋广告语
    pNiKeShoes->Show();

    // 构造优衣库衣服的工厂对象
    ConcreteFactory uniqloFactory;
    // 创建优衣库衣服对象
    Clothe *pUniqloClothe = uniqloFactory.CreateProduct();
    // 打印优衣库广告语
    pUniqloClothe->Show();

    // 释放资源
    delete pNiKeShoes;
    pNiKeShoes = NULL;

    delete pUniqloClothe;
    pUniqloClothe = NULL;

    return 0;
}

  • 输出结果:

[root@lincoding factory]# ./templateFactory 
我是耐克球鞋,我的广告语:Just do it
我是优衣库衣服,我的广告语:I am Uniqlo


产品注册模板类+单例工厂模板类

前面的模板工厂虽然在新增产品的时候,不需要新增具体的工厂类,但是缺少一个可以统一随时随地获取指定的产品对象的类。

还有改进的空间,我们可以把产品注册的对象用std::map的方式保存,通过key-valve的方式可以轻松简单的获取对应的产品对象实例。

实现大致思路:

  • 把产品注册的功能封装成产品注册模板类。注册的产品对象保存在工厂模板类的std::map,便于产品对象的获取。

  • 把获取产品对象的功能封装成工厂模板类。为了能随时随地获取指定产品对象,则把工厂设计成单例模式。

UML图:

c++工厂模式_第2张图片

产品注册模板类+单例工厂模板类:

  • IProductRegistrar为产品注册抽象类,模板参数 ProductType_t 表示的类是产品抽象类(如ShoesClothe)。提供了产品对象创建的纯虚函数CreateProduct
  • ProductFactory为工厂模板类,模板参数 ProductType_t 表示的类是产品抽象类(如ShoesClothe)。用于保存注册产品对象到std::map中和获取对应的产品对象。
  • ProductRegistrar为产品注册模板类,模板参数 ProductType_t 表示的类是产品抽象类(如ShoesClothe),ProductImpl_t 表示的类是具体产品(如NikeShoesUniqloClothe)。用于注册产品到工厂类和创建产品实例对象。

表示的类是具体产品(如NikeShoes、UniqloClothe)。用于注册产品到工厂类和创建产品实例对象。
// 基类,产品注册模板接口类
// 模板参数 ProductType_t 表示的类是产品抽象类
template
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 ProductFactory
{
public:
   // 获取工厂单例,工厂的实例是唯一的
   static ProductFactory &Instance()
   {
      static ProductFactory instance;
      return instance;
   }

   // 产品注册
   void RegisterProduct(IProductRegistrar *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 *> m_ProductRegistry;
};

// 产品注册模板类,用于创建具体产品和从工厂里注册产品
// 模板参数 ProductType_t 表示的类是产品抽象类(基类),ProductImpl_t 表示的类是具体产品(产品种类的子类)
template
class ProductRegistrar : public IProductRegistrar
{
public:
   // 构造函数,用于注册产品到工厂,只能显示调用
   explicit ProductRegistrar(std::string name)
   {
      // 通过工厂单例把产品注册到工厂
      ProductFactory::Instance().RegisterProduct(this, name);
   }

   // 创建具体产品对象指针
   ProductType_t *CreateProduct()
   {
      return new ProductImpl_t();
   }
};

  • main函数,通过ProductRegistrar注册各种不同类型产品,在统一由ProductFactory单例工厂获取指定的产品对象。

int main()
{
   // ========================== 生产耐克球鞋过程 ===========================//
   // 注册产品种类为Shoes(基类),产品为NiKe(子类)到工厂,产品名为nike
   ProductRegistrar nikeShoes("nike");
   // 从工厂获取产品种类为Shoes,名称为nike的产品对象
   Shoes *pNiKeShoes = ProductFactory::Instance().GetProduct("nike");
   // 显示产品的广告语
   pNiKeShoes->Show();
   // 释放资源
   if (pNiKeShoes)
   {
      delete pNiKeShoes;
   }

   // ========================== 生产优衣库衣服过程 ===========================//
   // 注册产品种类为Clothe(基类),产品为UniqloClothe(子类)到工厂,产品名为uniqlo
   ProductRegistrar adidasShoes("uniqlo");
   // 从工厂获取产品种类为Shoes,名称为adidas的产品对象
   Clothe *pUniqloClothe = ProductFactory::Instance().GetProduct("uniqlo");
   // 显示产品的广告语
   pUniqloClothe->Show();
   // 释放资源
   if (pUniqloClothe)
   {
      delete pUniqloClothe;
   }

   return 0;
}

  • 输出结果:

[root@lincoding factory]# ./singleFactory 
我是耐克球鞋,我的广告语:Just do it
我是优衣库衣服,我的广告语:I am Uniqlo

你可能感兴趣的:(c++工厂模式)