天天看點

泛型産品注冊模闆類 + 單例工廠模闆類

C++

#include <iostream>
#include <map>

/***********************/
// 基類 鞋子
class Shoes
{
public:
    virtual void Show() = 0;
    virtual ~Shoes() {}
};

// 耐克鞋子
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;
    }
};

// 基類 衣服
class Clothe
{
public:
    virtual void Show() = 0;
    virtual ~Clothe() {}
};

// 優衣庫衣服
class UniqloClothe : public Clothe
{
public:
    void Show()
    {
        std::cout << "我是優衣庫衣服,我的廣告語:I am Uniqlo" << std::endl;
    }
};

// 盜版衣服
class DaoBanClothe : public Clothe
{
public:
    void Show()
    {
        std::cout << "我是盜版衣,我的廣告語:想怎麼盜版就怎麼盜版。" << std::endl;
    }
};

/**************************************/


// 基類,産品注冊模闆接口類
// 模闆參數 ProductType_t 表示的類是産品抽象類
template <typename 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 <typename 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 <typename ProductType_t, typename 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");
    ProductRegistrar<Shoes, AdidasShoes> adidasShoes("adidas"); // 如果相同鍵值,會覆寫前面的。如果還是 nike,會用 adidas 的資訊覆寫掉前面的。
    // 從工廠擷取産品種類為Shoes,名稱為nike的産品對象
    Shoes* pNiKeShoes = ProductFactory<Shoes>::Instance().GetProduct("nike");
    Shoes* pAdidasShoes = ProductFactory<Shoes>::Instance().GetProduct("adidas");
    // 顯示産品的廣告語
    pNiKeShoes->Show();
    pAdidasShoes->Show();
    // 釋放資源
    if (pNiKeShoes)
    {
        delete pNiKeShoes;
    }
    if (pAdidasShoes != nullptr) {
        delete pAdidasShoes;
        pAdidasShoes = nullptr;
    }

    std::cout << std::endl;

    // ========================== 生産優衣庫衣服過程 ===========================//

    // 注冊産品種類為Clothe(基類),産品為UniqloClothe(子類)到工廠,産品名為uniqlo
    ProductRegistrar<Clothe, UniqloClothe> uniqloCloth("uniqlo");
    ProductRegistrar<Clothe, DaoBanClothe> daobanCloth("daoban");
    // 從工廠擷取産品種類為Shoes,名稱為adidas的産品對象
    Clothe* pUniqloClothe = ProductFactory<Clothe>::Instance().GetProduct("uniqlo");
    Clothe* pDaobanClothe = ProductFactory<Clothe>::Instance().GetProduct("daoban");
    // 顯示産品的廣告語
    pUniqloClothe->Show();
    pDaobanClothe->Show();

    // 釋放資源
    if (pUniqloClothe)
    {
        delete pUniqloClothe;
    }
    if (pDaobanClothe != nullptr) {
        delete pDaobanClothe;
        pDaobanClothe = nullptr;
    }

    return 0;
}      

輸出:

我是耐克球鞋,我的廣告語:Just do it
我是阿迪球鞋,我的廣告語:Impossible is nothing.

我是優衣庫衣服,我的廣告語:I am Uniqlo
我是盜版衣,我的廣告語:想怎麼盜版就怎麼盜版。      

參考: