之前在代码重构书中有了解过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