自动注册工厂消灭switch-case

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/Shreck66/article/details/50459518

之前在代码重构书中有了解过java中的反射机制可以消除switch-case,详情可以参考这篇博客http://blog.csdn.net/wwh578867817/article/details/49309789。那么我们的C++有没有类似干掉switch-case的方法?

1原始的工厂是如何创建派生类对象的

假如我们有个基类为Father,它有好多继承类分别为Son1,Son2,…
那么我们原始工厂(用来创建其子类对象)方法也就是用switch-case来实现
伪代码如下

Message* create(int type)
{
    switch (type) 
    {
    case _Son1_:
        m = new Son1;
        break;
    case _Son2_:
        m = new Son2;
        break;
    case _Son3_:
        m = new Son3;
        break;
    case _Son4_:
        m = new Son4;
        break;
    case __Son5:
        m = new Son5;
        break;
    default:
        break;
    }
}

如果我们的case语句少点还好,一旦有好多的case语句,我们的代码维护起来就会变得很麻烦,那么我们有什么办法可以像java的反射机制一样干掉常常的switch-case语句呢?

2.自动注册的对象工厂

没错我们可以实现一个有自动注册功能的对象工厂就可以干掉switch-case了

为什么其可以干掉switch-case?

首先我们的自动注册对象工厂会维护一个map集合,该map的key便是我们上述的switch-case里的type,value为一个可调用对象,该可调用对象会调用具体某个Son类的构造函数,然后返回新生成对象的额指针。在每个子类的头文件中,我们就会将该子类的type和对应的可调用对象插入到map中,这样当我们程序中要生成某个具体子类对象时,我们的工厂便会更具type找到map中对应的可调用对象,然后执行可调用对象便可生成该type所对应的类对象了

具体实现如下

我们把父类看做基础消息,命名为Message,继承其的消息分别为Message2…等
父类代码

#pragma once

class Message
{
    public:
        virtual ~Message(){}

        virtual void foo()//由子类自己实现的接口
        {

        }
};

工厂类的代码实现

#pragma once

#include <map>
#include <string>
#include <functional>
#include <memory>
#include "message.h"

class Factory
{
    public:
        template<typename T>
        struct Register //用于将特定构造函数的可调用对象插入map的注册类
        {
            Register(const std::string &key)
            {
                Factory::get().map_.emplace(key,[]{return new T();});//lambda表达式作为可调用对象       
            }
            template<typename... Args>//构造函数为有参数时
            Register(const std::string &key,Args... args)
            {
                Factory::get().map_.emplace(key,[&]{return new T(args...);});
            }
        };

        static Message *produce(const std::string &key)//生产具体的对象
        {
            if(map_.find(key) == map_.end())
            {
                throw std::invalid_argument("the message key is not exist!");
            }
            return map_[key](); //注意lambda在这里执行
        }

        //用智能指针来管理裸指针
        static std::unique_ptr<Message> produce_unique(const std::string &key)
        {
            return std::unique_ptr<Message>(produce(key));
        }

        static std::shared_ptr<Message> produce_shared(const std::string &key)
        {
            return std::shared_ptr<Message>(produce(key));
        }
    private:
        Factory(){};
        Factory(const Factory&) = delete;
        Factory(Factory &&) = delete;

        static Factory &get()//每次返回静态局部变量多额引用可轻松实现类的单例模式
        {
            static Factory instance;
            return instance;
        }
        static std::map<std::string,std::function<Message *(void)>> map_;   //保存type和可调用对象的map
};

std::map<std::string,std::function<Message *()>> Factory::map_;

#define REGISTER_MESSAGE_VNAME(T) reg_msg_##T##_
#define REGISTER_MESSAGE(T,key, ...) static Factory::Register<T> REGISTER_MESSAGE_VNAME(T)(key,##__VA_ARGS__)

类Message1的代码

#pragma once

#include "message.h"
#include "factory.h"
#include <iostream>

class Message1 : public Message
{
    public:
        Message1()
        {
            std::cout << "Message1" << std::endl;
        }


        ~Message1()
        {

        }

        void foo()override  //自己实现的接口
        {
            std::cout << "Message1" << std::endl;
        }
};

REGISTER_MESSAGE(Message1,"Message1");//通过此将执行Message1构造函数的可调用对象插入到map中

类Message2的代码

#pragma once

#include "message.h"
#include "factory.h"
#include <iostream>

class Message2 : public Message
{
    public:
        Message2()
        {
            std::cout << "Message2" << std::endl;
        }

        Message2(int a)
        {
            std::cout<< "Message2" <<std::endl;
        }

        ~Message2()
        {

        }

        void foo()override
        {
            std::cout << "Message2" << std::endl;
        }
};

测试程序的代码


#include "message1.h"
#include "message2.h"
#include "message.h"

int main(int argc,char **argv)
{
  Message *p = Factory::produce("Message1");
  Message *p1 = Factory::produce("Message2");
  p->foo();
  p1->foo();
  delete p;
  delete p1;

  return 0;
}

执行结果为
这里写图片描述
这样我们就可以用自动注册工厂神奇的消灭掉switch-case了
详细代码请到https://github.com/Miaoshuai/factory

猜你喜欢

转载自blog.csdn.net/Shreck66/article/details/50459518