Modern C++ Design 笔记 第八章 Object Factories

来源:互联网 发布:电影矩阵 编辑:程序博客网 时间:2024/05/17 00:54

在前面一章的描述中说实话有点浅尝辄止,淡淡的扯了前面几节就黔驴技穷了,当然也不想再狗尾续貂了,所以很高兴开始了新的一章的征程 Object Factories。


说起这章,我们得先说说Factory模式, 这个模式的起源在于我们有太多的类似ConcreteClass* p = new ConcreteClass 的申明,而这些静态的申请在这里限定了p的类型, 我们的想法就是如果可以不显示把p的类型在这里显示出来,这时候一个factory在包装之后一个createInstance之类的轻便的接口可以帮助我们解决很多问题。这里援引了wikipedia上的一些说明:

The factory method pattern is an object-oriented design pattern. Like other creational patterns, it deals with the problem of creating objects (products) without specifying the exact class of object that will be created. The factory method design pattern handles this problem by defining a separate method for creating the objects, whose subclasses can then override to specify the derived type of product that will be created. More generally, the term factory method is often used to refer to any method whose main purpose is creation of objects.

但是像世界上没有完美的东西一样,createInstance带来的问题就是如果显示的指定你需要创建的实例具体类型。不开玩笑的是我确实曾经看到书中提到的形似不和谐的代码,这里是当初看到的UIFactory的代码片段。
  1. UIElement* createInstance(int elementID)
  2. {
  3.           UIElement * p = NULL;
  4.           switch(elementID)
  5.           {
  6.             case 1:
  7.                    p = new UILabel; 
  8.                    break;
  9.             case 2:
  10.                    p = new UITextField;
  11.                    break;
  12.             case 3:
  13.                    p = new UIButton;
  14.                    break;
  15.             /*
  16.                    even more, we needn't list here
  17.             */ 
  18.            default: 
  19.                    break; 
  20.           }
  21. }
这样的代码其实离我们的生活真的很近:) 可能很多Factory在最初设计的时候就是这样的(这个类似的代码取自一个非常资深的德国开发团队)。如果这些其中的1, 2, 3...确定下来了不再更改可能还可以接受,但是当需要添加删除的时候,我们就开始皱眉头了。很显然的这里的缺陷在于每次我需要添加和删除新的节点的时候(当时也确实很多添加的需求),我这一部分的代码始终在修改中而不能完全的符合所谓的开闭原则。所以不能算一个很好的解决方案。(更进一步的说,如果int的数量比较大的,这样依次的值比对也不是一个高效的做法)。
        所以,书上也提供了一种比较常见的解决方案,那就是关联性的容器。(尽管这里给出一个STL::Map,但是实际上Loki也并没有采用Map而是使用了类似的AssocVector。)这里就可以动态的添加新的数据类型了,这里通过一个Register的接口传入typeid(这里的ID还不是RTTI中的那个ID,应该说这只是一种独特的表示,可以是一个string或者int,enum等等)和对应的create函数。这样就能把匹配类型的事情交给容器去做(而且这部分代码是肯定不会改变的)。
        这里的描述都是概念性的,真正在应用的时候,Loki还是会把这个概念清晰的方案整的很恢弘。这部书中给出了一些代码片段值得我们一看
  1. template
  2. <
  3. class AbstractProduct,
  4. typename IdentifierType,
  5. typename ProductCreator,
  6. template<typename, class>
  7. class FactoryErrorPolicy
  8. >
  9. class Factory
  10. public FactoryErrorPolicy<IdentifierType, AbstractProduct>
  11. {
  12. bool Register(const IdentifierType& id, ProductCreator creator)
  13. {
  14. }
  15. bool Unregister(const IdentifierType& id)
  16. {
  17. }
  18. AbstractProduct* CreateObject(const IdentifierType& id)
  19. {
  20. }
  21. }
这是一个大致的结构性的头文件定义,当然经过和既有的元素组合,我们可以看到更精致的申明,比如说:
typedef SingletonHolder
<
Factory
<
Shape, std::string, Functor<Shape*>
>
>
ShapeFactory;
在这里首先把Factory放到了SingletonHolder里面了,然后原来的create()函数也被Functor取代了:)深刻的感觉到,在随着读书的深入,慢慢的作者已经慢慢地把理解推向了应用的新高度了。。。
原创粉丝点击