设计模式-模板工厂

        在上一节的抽象工厂中,已经实现对某一品牌产品工厂的设计了,但是抽象工厂依然存在一定的问题,就是一旦需要额外新增生产别的产品的话,就依然需要对工厂类进行修改,这显然违背了“对扩展开放,对修改封闭”的原则。为此,提出了模板工厂的设计模式,让整个工厂类从具体的产品中抽离开,利用“模板编程”的思想,即使产品种类发生了变化,做到依然不需要更改工厂类。

        如上图所示,在抽象工厂类中,我们定义了一个produce纯虚函数,该纯虚函数返回抽象产品类的指针。而在具体的工厂类中,当传递了抽象产品类以及具体产品类之后,produce函数返回具体产品类的指针,从而做到了工厂类完全独立于了产品。

1. 抽象工厂类

        本文的抽象产品类以及具体产品类的写法与上一节完全一致,因此在这就不在赘述了。本节主要介绍一个抽象工厂类,在抽象工厂类中定义了一个纯虚函数,然后该纯虚函数只返回抽象产品类的指针即可。

template<class AbastractProduce>
class Factory{
public:
    Factory(){};
    virtual ~Factory(){};
    virtual AbastractProduce* produce()=0;
};

2. 具体工厂类

        在具体工厂类中,需要重写produce函数,然后再返回具体产品类的指针即可:

template<class AbstractProduce, class ConcertProduce>
class NikeFactory: public Factory<AbstractProduce>{
public:
    NikeFactory(){};
    ~NikeFactory(){};
    ConcertProduce* produce(){
        cout << "生产产品了" << endl;
        return new ConcertProduce();
    }
};

3. 主函数测试

        对上述代码进行测试,其中每个Factory工厂类就是对某一个品牌工厂的抽象,该工厂类能够生产与该品牌相关的所有产品:

int main(){
    NikeFactory<Clothes, NikeClothes>* nikeClothes = new NikeFactory<Clothes, NikeClothes>();
    nikeClothes->produce()->wear();

    NikeFactory<Shoes, NikeShoes>* nikeShoes = new NikeFactory<Shoes, NikeShoes>();
    nikeShoes->produce()->show();
    return 0;
}

        下面是具体的运行结果:

 

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

        在上述的模板工厂模式中,缺少一个可以随时获取所有产品的类,也就是说,我们能不能给工厂输入产品的名称,就可以获取该类产品的对象了?为了我们可以额外添加一个产品注册模板类,每中产品首先需要在产品注册模板中进行注册,然后才能从工厂中生产产品。需要补充的是,工厂类一般都是单例模式,为此我们可以使用静态局部变量的形式,把工厂类封装成一个单例模式。

         如上图所示,为了实现产品模板类与工厂类数据的共享,就需要在产品模板类的构造函数中调用工厂类的注册方法,使得工厂类中存有<string, ProduceRegistrar>的数据对,从而后续可以通过名称就可以得到对应的注册模板了,实现了工厂对一类产品的管理。其中就涉及到五中类别:抽象产品类,具体产品类,抽象注册类,具体注册类以及模板工厂类

4.1 抽象产品类与具体产品类

        抽象产品类以及具体产品类已经在前文叙述过了,在这里就不再赘述。

#include <iostream>
#include <map>
#include <string>

using namespace std;

class Shoes{
public:
    virtual void show()=0;
};

class Clothes{
public:
    virtual void wear()=0;
};

class NikeShoes:public Shoes{
public:
    void show(){
        cout << "这是耐克鞋子" << endl;
    }
};

class UniqloClothes:public Clothes{
public:
    void wear(){
        cout << "这是优衣库的衣服" << endl;
    }
};

4.2 抽象注册类

        在抽象具体类中,需要将produce()方法变成纯虚函数!!而析构函数以及复制操作运算符也需要变成protected的,这是为了不希望用户创建这个抽象注册类的对象,而其继承类则可以使用。

// 抽象注册模板类
template<class AbstractProduct>
class AbstractRegistrar{

protected:
    virtual ~AbstractRegistrar<AbstractProduct>(){};
    AbstractRegistrar<AbstractProduct>& operator=(const AbstractRegistrar<AbstractRegistrar>& absR){};
public:
    AbstractRegistrar<AbstractProduct>(){};
    // 生产产品
    virtual AbstractProduct* produce() = 0;
};

4.3 模板工厂类

        抽象工厂类一定要放在抽象注册类之后,而在具体注册类之前定义。在模板工厂类中,需要定义注册方法以及生产方法,这个生产方法并不会直接创建一个产品对象,而是会调用注册类中的生产方法,这样可以保证注册的产品对象与工厂中生产的产品是一致的。

// 抽象模板工厂类(单例模式)
template<class AbstractProduct>
class Factory{
private:
    Factory<AbstractProduct>(){};
    ~Factory<AbstractProduct>(){};
    Factory<AbstractProduct>(const Factory<AbstractProduct>&){};
    //Factory<AbstractProduct>& operate=(const Factory<AbstractProduct>& fact){};
    map<string, AbstractRegistrar<AbstractProduct>*> record;
public:
    static Factory<AbstractProduct>* getInstance(){
        static Factory<AbstractProduct> instance;
        return &instance;
    }
    // 对注册类注册到工厂类中
    void regist(const string& name, AbstractRegistrar<AbstractProduct>* registrar){
        record[name] = registrar;
    };
    // 进行生产
    AbstractProduct* produce(const string& name){
        if(record.find(name) != record.end()){
            return record[name]->produce();
        }
        cout << "没有找到对应的产品类" << endl;
        return nullptr;
    };
};

 4.4 具体注册类

        在具体注册类中,就需要在注册类的构造函数中将产品的名称以及对应的注册对象记录在工厂类中(记录在案)。这样在注册类中可以使用工厂类数据,而在工厂类中也可是使用注册类的数据,这两者是相关依赖的关系。

// 具体注册模板类
template<class AbstractProduct, class ConcertProduct>
class Registrar:public AbstractRegistrar<AbstractProduct>{
public:
    explicit Registrar<AbstractProduct,ConcertProduct>(const string& name){
        // 在构造函数中就向工厂类中进行注册
        Factory<AbstractProduct>::getInstance()->regist(name,this);
    }
    ConcertProduct* produce(){
        return new ConcertProduct();
    }  
};

4.5 实验测试

         下面就是测试的代码:

int main(){
    const string name = "nike";
    Registrar<Shoes, NikeShoes> NikShoesRegister(name);
    Shoes* nikeShoes = Factory<Shoes>::getInstance()->produce(name);
    nikeShoes->show();
    return 0;
}

5. 参考文献

(1) C++ 深入浅出工厂模式(进阶篇) - 知乎

  • 4
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值