自动注册工厂消灭switch-case
之前在代码重构书中有了解过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 onceclass 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
自动注册工厂消灭switch-case相关推荐
- 三步实现自动注册工厂替代switch语句(c++)
概述 在学长博客里看到了使用自动注册工厂替代switch语句的文章,想到可以将其用到自己的项目里,就照猫画虎学习着也实现了一个. 这里并不是用其替代创建派生类的传统Factory,而是为了替代服务器中 ...
- 基于模板的自动注册工厂模式(C++11实现)
工厂类 factory.h #pragma once#include <functional> #include <memory> #include <unordered ...
- 用C++实现一个自动注册的工厂
原文地址:http://geek.csdn.net/news/detail/48963 工厂方法是最简单地创建派生类对象的方法,也是很常用的,工厂方法内部使用switch-case根据不同的key去创 ...
- C++中实现自动注册的工厂
很长时间没有更新博客了,不是博主懒,是因为博主在帮研究生妹子弄硕士论文,定位方面的,被imu,行人航迹,激光匹配各种虐,不说了,都是泪. Factory模式,在工程中多用了创建派生类实例,内部一般使用 ...
- c++11实现一个自动注册的工厂模式
实现动机 最近项目中需要用到工厂模式,但是普通的工厂模式面临一个问题,每新增一个派生类,都需要在工厂中加一个case分支,这样就会频繁地修改工厂的代码,而且随着派生类越来越多,case分支也逐渐增多, ...
- C++11实现一个自动注册的工厂
转自:https://www.cnblogs.com/qicosmos/p/5090159.html 实现动机 工厂方法是最简单地创建派生类对象的方法,也是很常用的,工厂方法内部使用switch-ca ...
- 工厂模式之消除switch/case语句
2019独角兽企业重金招聘Python工程师标准>>> 我们在平时的编码中,我们经常会遇到这样的情况: 使用过多的switch/case 或者 if else 语句,非常不爽,也违背 ...
- ARouter init 源码解析(自动注册的实现)
概要 使用ARouter,我们只需要在必要的地方加上注解,然后在application中init Arouter就可以直接通过代码进行路由跳转了. 为什么我们可以不用写任何注册的代码,就直接跳转到相关 ...
- 微信扫码 - 关注公众号后网站自动注册并登录的实现
微信扫码 - 关注公众号后网站自动注册并登录的实现 需求描述 在自己网站上点击微信登录,网站自己弹出一个二维码.扫描二维码后弹出公众号的关注界面.只要一关注公众号网站自动登录.第二次扫描登录的时候网站 ...
最新文章
- LruCache缓存机制
- strstr(),strchr()
- Linux中设置定期备份oracle数据库
- ZigBee On Windows Mobile—利用CF卡接口外扩
- oracle索引总结
- 【java读书笔记】——java的异常处理
- [css] 写出主流浏览器内核私有属性的css前缀
- CVPR2021 用更好的目标检测器提取视觉特征!微软提出VinVL,基于更好的视觉特征,达到更强的多模态性能...
- 算法(第4版) Chapter 5.2 单词查找树
- Java基础——枚举类的使用教程
- 5G(4)---5G 标准
- 微软的基础服务器,微服务器当道 微软云端基础构架揭秘
- mysql小结果集驱动大结果集_具体优化查询语句的指导原则小结果集驱动大结果集避免子查询...
- 判断年月日是否正确及获取当前天的前一天或前一个月
- CentOS 7.4安装postgresql96
- 嵌入式Linux系统驱动hp1020打印机
- vue 下载pdf文件
- 05_经典电影台词(一)
- 金山WPS计算机视觉算法工程师
- 一年风雨几度寒,一杯浊酒敬虎年