站点图标

设计模式 02 工厂方法模式

一、意图

  定义一个用于创建对象的接口,让子类决定实例化哪一个对象。说人话就是:将创建对象的工作交给一个“工厂”来完成。

二、UML图

图1:工厂方法模式UML

图1:工厂方法模式UML[/caption]
  我们在抽象Creator中的的FactoryMethod如下,这里的形式参数可以设置一些值,以选择返回特殊的产品(这里使用模板而没用这种技巧):
template<class AbstractProduct_t>
class AbstractFactory
{
public:
    virtual AbstractProduct_t* CreateProduct() = 0;
};

  在下面的具体Creator中,我们返回创建的产品:

template<class AbstractProduct_t, class ConcreteProduct_t>
class ConcreteFactory
{
public:
    AbstractProduct_t* CreateProduct()
    {
        return new ConcreteProduct_t();
    }
};

三、实例

  下面我们来看一段实例,我们有两个抽象产品:shoes和clothe,我们的具体产品是nikeShoes和uniqloClothe。我们通过c++的模板操作来对工厂模式做一个改进:

// 抽象类(产品) 01 : 鞋子
class Shoes
{
public:
    virtual void show() = 0;
};

// 抽象类(产品) 02 : 衣服
class Clothe
{
public:
    virtual void show() = 0;
};

// 具体产品 01 : Nike Shoes
class NikeShoes : public Shoes
{
public:
    void show()
    {
        std::cout << "Nike Shoes" << std::endl;
    }
};

// 具体产品 02 : Uniqlo Clothe
class UniqloClothe : public Clothe
{
public:
    void show()
    {
        std::cout << "Uniqlo Clothe" << std::endl;
    }
};

// 工厂方法同上

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;
}

四、缺陷与改进

  上面的方法比较死板,如果想要完成(服装类型 x 品牌)的组合则需要使用抽象工厂模式(Abstract Factory),这个模式我们将在下一篇文章中介绍。这里我们引入注册机的机制来创建一种新的工厂模式,产品注册模板类+单例工厂模板类:

图2:模板注册机+单例工厂 UML

图2:模板注册机+单例工厂 UML[/caption]
  我们的产品保持不变:Shoes、NikeShoes、Clothe和UniqloClothe。

4.1 抽象注册机 – IProductRegister

template<class ProductType_t>
class IProductRegister
{
private:
    // 禁止外部拷贝和赋值
    IProductRegister(const IProductRegister&) = delete;
    const IProductRegister& operator=(const IProductRegister&) = delete;
protected:
    // 禁止外部构造与析构,允许子类其他函数调用
    IProductRegister() {}
    virtual ~IProductRegister() {}
public:
    // 获取抽象产品接口
    virtual ProductType_t* CreateProduct() = 0;
};

4.2 工厂 – ProductFactory

template<class ProductType_t>
class ProductFactory
{
private:
    // 禁止外部构造与析构
    ProductFactory() {}
    ~ProductFactory() {}

    // 禁止外部拷贝与赋值
    ProductFactory(const ProductFactory&) = delete;
    const ProductFactory& operator=(const ProductFactory&) = delete;

    // 保存已经注册的产品
    std::map<std::string, IProductRegister<ProductType_t>*> m_ProductRegistry;

public:
    // 或得工厂单例、工厂实例唯一
    static ProductFactory<ProductType_t>& Instance()
    {
        static ProductFactory<ProductType_t> instance;
        return instance;
    }

    // 产品注册
    void RegisterProduct(IProductRegister<ProductType_t>* p_register, std::string productName)
    {
        m_ProductRegistry[productName] = p_register;
    }

    ProductType_t* GetProduct(std::string productName)
    {
        // 已注册则返回产品
        if (m_ProductRegistry.count(productName) > 0)
        {
            return m_ProductRegistry[productName]->CreateProduct();
        }
        std::cout << "product not exist" << std::endl;
        return nullptr;
    }
};

4.3 具体注册机 – ProductRegister

template<class ProductType_t, class ProductImpl_t>
class ProductRegister : public IProductRegister<ProductType_t>
{
public:
    // 显式将产品注册到工厂
    explicit ProductRegister(std::string productName)
    {
        ProductFactory<ProductType_t>::Instance().RegisterProduct(this, productName);
    }

    ProductType_t* CreateProduct()
    {
        return new ProductImpl_t();
    }
};

4.4 在main中使用

int main()
{
    // 注册shoes(basic), NikeShoes(dep)到工厂,取名为NikeShoes
    ProductRegister<Shoes, NikeShoes> registeNikeShoes("NikeShoes");
    Shoes* pNikeShoesPtr = ProductFactory<Shoes>::Instance().GetProduct("NikeShoes");
    pNikeShoesPtr->show();

    pNikeShoesPtr != nullptr ? delete pNikeShoes :
        void();

    // 注册colthe - uniqloClothe到工厂,取名为UniqloClothe
    ProductRegister<Clothe, UniqloClothe> resgiteUniqloClothe("UniqloClothe");
    Clothe* pUniqloClothePtr = ProductFactory<Clothe>::Instance().GetProduct("UniqloClothe");
    pUniqloClothePtr->show();

    pUniqloClothePtr != nullptr ? delete pUniqloClothe :
        void();

    return 0;
}
退出移动版