动态工厂 一种替代简单工厂的完美方式

简单工厂最大的一个缺点就是,增加新的业务类时,要手动增加else分支或者case, 不方便扩展。而动态工厂不同,它只需要注册一下,就可以使用。
初看动态工厂时,可能会有点懵,接下来我们通过下面几步,对这个实用的工具进行下分析。

  1. 用字符串做key,用创建类的函数指针做value,通过这个全局变量map,获取创建函数从而创建对象,精简代码如下。理解这一版,就理解了动态工厂的关键。
#include <iostream>
#include <map>
#include <string>
using namespace std;

class Base {};
class A : public Base {
   public:
    A() { cout << "A" << endl; }
};
class B : public Base {
   public:
    B() { cout << "B" << endl; }
};

Base* createA() { return new A(); }
Base* createB() { return new B(); }

// 定义一个函数指针返回类型
using ConcreteCreator = Base* (*)();
// key: type, value: 函数指针
std::map<string, ConcreteCreator> fac;

int main() {
    // 注册
    fac.insert({"A", createA});
    fac.insert({"B", createB});

    // 使用
    auto it = fac.find("A");
    if (it != fac.end()) {
        Base* b = (it->second)();  // 相当于  Base* b = new A();
        delete b;
    }

    return 0;
}
  1. 改进, 在1中有一个缺点,就是每新增一个实现类,就要对应增加一个create函数, 这样其实也不比简单工厂强多少。 我们是用模板函数替代它,这样就会省掉这个函数。
...
template <typename BASE, typename DERIVED>
BASE* create() {
    return new DERIVED();
}

// 定义一个函数指针返回类型
using ConcreteCreator = Base* (*)();
// key: type, value: 函数指针
std::map<string, ConcreteCreator> fac;

int main() {
    // 注册
    fac.insert({"A", create<Base, A>});
    fac.insert({"B", create<Base, B>});
..
  1. 1和2理解了之后,再来看下面代码
#pragma once
#include <map>
#include <string>
using namespace std;

// 这里定义一个泛型单例类,专门用来生成派生类,并返回基类指针
template <typename Object, typename ConcreteObject>
class ConcreteCreator {
   public:
    static Object* createObject() { return new ConcreteObject(); }
};

template <typename Object>
class Creator {
   public:
    //实例化,全局唯一
    static Creator& Instance() {
        static Creator<Object> instance;
        return instance;
    }

   private:
    Creator() {}
    ~Creator() {}
    Creator(Creator&);  // 不准拷贝

   public:
    using CreateObjectDelegate = Object* (*)();  //类型定义,关联第10行
    using MapRegisterCreatorItem = std::map<std::string, CreateObjectDelegate>;

    template <typename ConcreteObject>
    void registerCreator(const std::string& _type) {
        mConcreteCreators[_type] =
            ConcreteCreator<Object, ConcreteObject>::createObject;
    }

    void unregisterAllCreators() { mConcreteCreators.clear(); }

    Object* createObject(const std::string& _type) {
        typename MapRegisterCreatorItem::iterator type =
            mConcreteCreators.find(_type);
        if (type != mConcreteCreators.end()) {
            CreateObjectDelegate create = type->second;
            if (create != 0) return create();
        }
        //找不到就返回nullptr
        return nullptr;
    }

   private:
    MapRegisterCreatorItem mConcreteCreators;  // 注册信息都存在这里
};

上面的代码看着很多,其实从1,2顺下来之后也不难理解。而且,完成之后,使用起来会非常方便。如下。并且它应用了泛型,这样就可以替代所有的简单工厂。

class Base {};
class A : public Base {
   public:
    A() { cout << "A" << endl; }
};
class B : public Base {
   public:
    B() { cout << "B" << endl; }
};


using CRT = Creator<Base>;
int main()
{
    //注册
	CRT &crt = CRT::Instance();
	crt.registerCreator<A>("A");	
	crt.registerCreator<B>("B");
    
    // 根据字符串获取对象
	Base *b = crt.createObject("A");
	delete b;
	return 0;	
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值