核心内容摘要
9.1樱花盛宴:秒变PPT大神,告别加班,效率飙升!
taodm翻译“我们知道这是什么吗”我指着放在前面金属台上的设备。
这是在冰原下勘探到的第一批物体之一。
珍妮摇着头。
”没呢伙计。
它可能是个奖杯飞船推进器儿童玩具或就只是垃圾。
上周我们曾认为将能源系统制造出来了供这个和其它一些设备用的但在加入燃料后什么也没发生。
随着能源的远去技术又重回到了画图板上但他们认为很快能搞定它。
.”“凭什么”“希望。
”我瞄了一下墙上的钟。
”好吧时间差不多了。
我在发抖我很冷。
每次我们要求勘探队给我们些新的东西来鼓捣时他们总弄出些新的不同的东西。
我真希望能弄明白哪怕其中任何一个。
”“我希望我们对从这个‘artifact factory’中出产的东西能知道得更多些。
”珍妮同意。
“这使我回想起以前发生在我身上的一些事在那时……”珍妮眨着她的眼睛。
”告诉为什么时候我们可以到个暖和的地方。
”“坏消息”我越过隔板向温迪嚷道。
“呒”她探起头。
“你知道我上周写的类的吧。
”“不是十分清楚说下去。
”我没在意。
”好吧”我继续着”我必须为它实现一个类厂。
Guru建议我看一下客户群写的类厂。
”“嗯于是”突然沮丧显现在她脸上”噢。
鲍勃写的是吧”我沉重地点点头。
”是的我唯一能给予他的称赞是 —每当我打开他的代码我都能学会有些事不该如何实现。
”温迪哈哈地笑着坐回位置上。
我叹了口气然后check out源码。
还好没我想象的那么坏。
只不过是极大量的if语句嵌套我做好了坏得多的准备的。
但已是够可怕的代码了所以根据Guru的忠告我准备实现一个Abstract Class Factory [1]。
由于没有多线程和并发的需求我决定将厂实现为singleton模式class BaseFactory{typedef std::auto_ptrBase (*BaseCreateFn)();typedef std::mapstd::string, BaseCreateFn FnRegistry;FnRegistry registry;BaseFactory() {}BaseFactory(const BaseFactory ); // Not implementedBaseFactory operator(const BaseFactory ); // Not implementedpublic:static BaseFactory instance() { static BaseFactory bf; return bf; }bool RegCreateFn(const std::string , BaseCreateFn);std::auto_ptrBase Create(const std::string ) const;};bool BaseFactory::RegCreateFn(const std::string className, BaseCreateFn fn){registry[className] fn;return true;}std::auto_ptrBase BaseFactory::Create(const std::string className) const{std::auto_ptrBase theObject(
;FnRegistry::const_iterator regEntry registry.find(className);if (regEntry ! registry.end()){theObject regEntry-second();}return theObject;}在Base的实现文件中我加入namespace{std::auto_ptrBase CreateBase(){return std::auto_ptrBase(new Base);}bool dummy BaseFactory::instance().RegCreateFn(“Base”, CreateBase);}“嗯不错”我思索着。
”向厂注册一个函数后生成实例就如数
1、
3那么简单”int main(){std::auto_ptrBase anObject BaseFactory::instance().Create(“Base”);}我继续生成一个派生类以测试通过厂来生成实例。
在派生类的实现中我加入namespace{std::auto_ptrDerived CreateDerived(){return std::auto_ptrDerived(new Derived);}bool dummy BaseFactory::instance().RegCreateFn(“Derived”, CreateDerived);}但编译器冷冷地阻住了我它提示不能将CreateDerived转换为所需类型。
在迷惑了好一阵之后我想起以前经历过的隐式地转换为指向Base的指针的问题 [2]。
我认识到我又一次遇到编译器不能进行隐式指针转换问题所以我稍稍修改了create函数namespace{std::auto_ptrBase CreateDerived(){return std::auto_ptrBase(new Derived);}bool dummy BaseFactory::instance().RegCreateFn(“Derived”, CreateDerived);}回顾一下基类我注意到注册代码几乎相同所以我写了个替代的宏#define REGISTER_CLASS(BASE_CLASS, DERIVED_CLASS) \namespace \{ \std::auto_ptrBASE_CLASS Create##DERIVED_CLASS() \{ \return std::auto_ptrBASE_CLASS(new DERIVED_CLASS); \} \bool dummyBaseFactory::instance().RegCreateFn( \#DERIVED_CLASS, Create##DERIVED_CLASS); \}使用这个宏很简单REGISTER_CLASS(Base, Base)“近一小时的工作做得不错”我在完成时嘟囔着。
“是的确实如此我的孩子。
但你还能做得更好。
”Guru轻柔的声音出现在身后时我还是会被吓一跳。
”什么”“这样展开的宏”她解释道”是难以阅读和理解的并且宏不是类型安全的。
还有这个bool变量是什么目的”“这个嘛”我有些抵触地答道”它是我唯一能想到的能确保注册函数被自动调用的方法。
我不想在每增加一个新类时都要修改典型厂的代码。
”她点点头。
”很聪明的想法我的孩子。
但是你的厂不足够通用。
会有越来越多的需要abstract factory的类。
我期望你创建这样一个厂能在它被应用的每个类层次上自动处理而不是要求修改create a factory that will handle, not require, modification for each class hierarchy it will be used on。
”“一个通用的abstract factory这有些苛求不是吗”“徒弟你从不畏惧挑战是吧‘Experience is by industry achieved... ““‘... and perfected by the swift course of time’”我接道[3]。
“我从不畏惧挑战但我不能将进度表置之不理地花费大量时间。
”“你已经几乎就做到了。
你所需要的就是考虑通用”她指点道。
“考虑通用……也就是说模板”我嚷着转向显示器。
几分钟之后我向身后瞄了一下Guru如出现时一样已悄悄地不见了。
我稍稍有些哆嗦又转回去继续工作。
过了一会儿我实现了一个厂模板template class ManufacturedType, typename ClassIDKeystd::stringclass GenericFactory{typedef std::auto_ptrManufacturedType (*BaseCreateFn)();typedef std::mapClassIDKey, BaseCreateFn FnRegistry;FnRegistry registry;GenericFactory();GenericFactory(const GenericFactory); // Not implementedGenericFactory operator(const GenericFactory); // Not implementedpublic:static GenericFactory instance();void RegCreateFn(const ClassIDKey , BaseCreateFn);std::auto_ptrManufacturedType Create(const ClassIDKey className) const;};我认为不是所有的类都用std::string作为键值所以我将键值类型作为一个模板参数。
所有函数的实现都和我在BaseFactory中写过的一模一样除了那个注册函数之外。
我用一个更优雅的模板来实现它的template class AncestorType, class ManufacturedType, typename ClassIDKeystd::stringclass RegisterInFactory{public:static std::auto_ptrAncestorType CreateInstance(){return std::auto_ptrAncestorType(new ManufacturedType);}RegisterInFactory(const ClassIDKey id){GenericFactoryAncestorType::instance().RegCreateFn(id, CreateInstance);}};现在每个从基类派生的类只需要增加一行代码就可以获得类型安全的creation函数RegisterInFactoryBase, Base registerMe(“Base”);模板的构造函数向creation registry注册它的类名[4]。
我向后一瞄正好看见Guru走过来。
我偷笑了一下; for once I was slightly ahead of her game至少有一次我预见了她的把戏。
”很好徒弟”她走到我身后说道。
”你的厂是通用的、可移植的不依赖于注册表、DLL或其它复杂的技巧。
”“但还有一个缺点”我打断说。
“因为这个注册行为依赖于一个static对象必须已被初始化如果在main被执行前就使用这个厂的话不确保所有的creation函数成功注册。
”“不错徒弟你的厂依赖于静态初始化顺序问题先知Cline讲解过这个问题 [5]。
”她转身离开了。
“等一下”我喊道。
Guru转过身。
我试图用一个文雅的方式询问盘据一个在我脑海中的问题。
Guru在等待时向耳后捋了一下头发。
”是关于鲍勃的。
既然他是如此差的一个程序员”我试图说道”怎么……”“为什么他还在这儿待着”Guru接道。
我点点头。
Guru思索了一下。
”你注意他老惹麻烦主管认为他有两把刷子不会犯错。
因为我们……嗯……过去鲍勃让他们相信我对他的抱怨是源于作为前妻的怀恨。
并且对他而言任何与我意见一致的人都是参与了我与他作对的阴谋他的说法不是我的。
”“真是无赖。
你为什么容忍他你可以另找一个同样的工作的。
”我掰着手指。
她耸了一下肩。
”除了鲍勃我喜欢这儿。
此外如果我离开了就不能享受这样挑他错的快乐了。
”我们都笑了。
”但是说真的”她接着说道”这个公司有着大量的成长机会。
比如我们新的医疗设备部门将需要一个软件开发的核心人物我在申请这个位置。
”“太好了祝你好运”我答道。
Guru点头示谢。
我回到我的工作间以完成abstract factory模板的最后部分。
消息传来时已是几天后的深夜。
但我直到第二天早上起来后才知道的。
还睡眼惺忪的我陷入混乱不同寻常的噪音使得我用手捂住耳朵缩成一团。
”怎么回事”我向已经先到的十几人嘟囔着他们正高兴地互相交谈 “一大早怎么那么开心”主管吉尔伯笑着答道”我们认为我们找到它了我的孩子我想我们是办到了。
”“什么”我一头雾水。
“看起来能源恢复了”珍妮说得很简捷。
[注释和参考][1] Gamma, Helm, Johnson, Vlissides. Design Patterns: Elements of Reusable Object-Oriented Software (Addison Wesley,