标签:
我们创建一个对象时,必须给出具体型别,new A也好,new B也罢。A,B都是对象的型别。我们向来反对写hardcode,但却在创建对象时必须hardcode。
如果需要根据用户的输入信息,或是网络反馈信息,或是文本文件信息来创建对象时,应该怎么办呢?
最初我们想法可能是这样的,伪代码
switch(Info) { case a: return new A; case b: return new B; ... default:... }
这就是大家都熟悉简单工厂模式,他虽然简单,但蕴含一个基本原则:根据value(a,b...)查找type(A,B...),利用type创建value(A*,B*...)。
利用对象工厂,我们创建对象时得到了解脱,无需写hardcode,不必给出类型,我们可以提供数字,字符串,以及特定格式信息来创建一个对象。
好的,这就是对象工厂存在的意义!
是的,不够完美。理由有三:
1 struct package 2 { 3 void * funcSet; 4 void * func; 5 size_t index; 6 string sig; 7 }; 8 9 template <typename ...> class TypeList {}; 10 11 template <typename AbstractProduct ,typename IdentifierType = string> class FactoryImpl 12 { 13 public: 14 template <typename... Arg> bool Register(const IdentifierType& id,const function<unique_ptr<AbstractProduct>(Arg...)>& creator) 15 { 16 17 static vector<function<unique_ptr<AbstractProduct>(Arg...)>> vf; 18 typename AssocMap::const_iterator i =associations_.find(id); 19 if(i!= associations_.end()) return false; 20 vf.push_back(creator); 21 return associations_.insert(typename AssocMap::value_type(id,package {&vf,&vf.back(),vf.size()-1,string(typeid(TypeList<Arg...>).name())})).second; 22 23 } 24 25 template <typename ... Arg > 26 bool UnRegister(const IdentifierType& id) 27 { 28 typename AssocMap::const_iterator i =associations_.find(id); 29 if(i != associations_.end()) 30 { 31 assert( 32 ((i->second).sig).compare(typeid(TypeList<Arg...>).name())==0 33 ); 34 auto vf=static_cast<vector<function<unique_ptr<AbstractProduct>(Arg...)>>*>((i->second).funcSet); 35 vf->erase(vf->begin()+(i->second).index); 36 } 37 38 return associations_.erase(id)==1; 39 } 40 41 template <typename... Arg> unique_ptr<AbstractProduct> Createobject(const IdentifierType& id,Arg&&... args) 42 { 43 typename AssocMap::const_iterator i =associations_.find(id); 44 45 if(i != associations_.end()) 46 { 47 assert(((i->second).sig).compare(typeid(TypeList<Arg...>).name())==0); 48 auto funp=static_cast<function<unique_ptr<AbstractProduct>(Arg...)>* >((i->second).func); 49 return (*funp)(std::forward<Arg>(args)...); 50 } 51 assert(false); 52 } 53 54 55 private: 56 typedef std::unordered_map<IdentifierType,package> AssocMap; 57 AssocMap associations_; 58 59 };
代码释疑:
因为没有在类模板使用可变参数,所以实现起来很是费劲,我现在倒觉得可以使用类模板带可变参数实现。这样类模板实例化的类,虽然只支持注册和调用参数固定调用体,但具有编译期类型检查的好处,Register和UnRegister均很容易实现。用户需要时,根据需要实例化模板即可。
template <typename AbstractProduct ,typename IdentifierType ,typename... Arg > class Factory { public: bool Register(const IdentifierType& id, std::function<unique_ptr<AbstractProduct> (Arg...)> creator) { return associations_.insert(typename AssocMap::value_type(id,creator)).second; } bool UnRegister(const IdentifierType& id) { return associations_.erase(id)==1; } unique_ptr<AbstractProduct> Createobject(const IdentifierType& id,Arg&&... args) { typename AssocMap::const_iterator i =associations_.find(id); if(i != associations_.end()) { return (i->second)(std::forward<Arg>(args)...); } assert(false); } private: typedef std::unordered_map<IdentifierType,std::function<unique_ptr<AbstractProduct> (Arg...)> > AssocMap; AssocMap associations_; };
需要注意一下,这代码因为使用变长模板参数,所以无法使用默认模板参数。
使用第一种实现方式,你只需要一个对象,即可搞定所有需求(UnRegister比较闹心)。具有运行期类型检查。
使用第二种实现方式,你要在不同场合下,实例化出类,并且创建出对象只支持注册某种调用格式调用体。而且具有编译期类型检查。
虽然在第一种方式上,下了很多功夫,但是我还是不推荐这种做法,除非真的有万不得已需要,非要把代码设计成这样。
春节前,最后一篇文章,转载请标明出处,谢谢。
标签:
原文地址:http://www.cnblogs.com/tangzhenqiang/p/4288623.html