QtAV中的各个模块大量使用的工厂模式,下面对其实现进行介绍。

工厂模式的使用

以 VideoRenderer 类为例子,他含有下面3个工厂模式相关的方法,Register方法用于给一个产品<class C>注册其ID和名称,create方法用于通过ID或名称生产一个产品实例。

  1. template<class C>
  2. static bool Register(VideoRendererId id, const char* name) { return Register(id, create<C>, name);}
  3. static VideoRenderer* create(VideoRendererId id);
  4. static VideoRenderer* create(const char* name);

例如,Direct2DRenderer 的注册和调用的具体方式如下:

注册

  1. VideoRenderer::Register<Direct2DRenderer>(VideoRendererId_Direct2D, "Direct2D");

生产一个Direct2DRenderer实例

  1. QtAV::VideoRenderer *renderer = VideoRenderer::create(VideoRendererId_Direct2D);

这种机制是如何实现的呢?下面以VideoRendererDirect2D为例来介绍。

工厂模式的实现过程

注意,上文以及下文中出现的 VideoRendererDirect2D 和 Direct2DRenderer 是等价的:

  1. // Direct2DRenderer 和 VideoRendererDirect2D 是等价的
  2. typedef Direct2DRenderer VideoRendererDirect2D;

在QtAV的视频输出等组件初始化的时候,会调用 QtAVWidget 工程中的 global.h 中声明的

  1. void registerRenderers()

来注册各个组件,这个函数就调用了

  1. extern void RegisterVideoRendererDirect2D_Man();

这个函数的定义位于 Direct2DRenderer.cpp 中

  1. void RegisterVideoRendererDirect2D_Man()
  2. {
  3. VideoRenderer::Register<Direct2DRenderer>(VideoRendererId_Direct2D, "Direct2D");
  4. }

这个函数调用使用了,位于 QtAV 工程的 VideoRenderer.h 的 VideoRenderer 类的 public 域下

  1. template<class C>
  2. static bool Register(VideoRendererId id, const char* name) { return Register(id, create<C>, name);}

这是一个static的模板函数,其中又调用了另一个 Register 函数,相关声明位于 QtAV 工程的 VideoRenderer.h 的 VideoRenderer 类的 private 域下

  1. template<class C>
  2. static VideoRenderer* create() {
  3. return new C();
  4. }
  5. typedef VideoRenderer* (*VideoRendererCreator)();
  6. static bool Register(VideoRendererId id, VideoRendererCreator, const char *name);

可以看到,传入给这个 Register 的第二个参数 create<C> 是这里定义的模板函数 create 的函数指针,这样的函数指针被 typedef 为了 VideoRendererCreator,作为 Register 的第二个形参的类型。

通过 Register 声明中的形参可以看出,注册 VideoRendererDirect2D 时,传入三个参数: VideoRendererId_Direct2D 作为的ID,VideoRendererCreator 函数指针作为生成时的回调函数,字符串 name 作为名字。这样就可以使用工厂传入ID或名字,工厂调用Creator回调函数得到想要的对象了。

不过这个 Register 的定义却不容易找到,原来,QtAV使用了一种宏把和工厂相关的方法都封装起来了!重头戏来啦,我们来看一看这是怎么实现的吧。

首先,可以在 VideoRenderer.cpp 文件中找到:

  1. FACTORY_DEFINE(VideoRenderer)

宏FACTORY_DEFINE(T)用于给工厂类相关的方法进行定义,这个宏的定义在 QtAV 工程下的 factory.h 文件中。 factory.h 这个文件中定义了工厂模式相关的宏和工厂基类 Factory ,下面给出 Factory 的声明:

  1. /*
  2. * Used in library, can not be used both in library and outside. so we don't need export it
  3. */
  4.  
  5. template <typename Id, typename T, class Class>
  6. class Factory : public Singleton<Class>
  7. {
  8. DISABLE_COPY(Factory)
  9. typedef Id ID;
  10. typedef T Type;
  11. typedef Type* (*Creator)();
  12. public:
  13. Type* create(const ID& id);
  14. template<class C>
  15. bool register_(const ID& id) { // register_<C>(id, name)
  16. std::pair<typename CreatorMap::iterator, bool> result = creators.insert(std::make_pair(id, create<C>));
  17. return result.second;
  18. }
  19.  
  20. //template <typename Func>
  21. bool registerCreator(const ID& id, const Creator& callback);
  22. bool registerIdName(const ID& id, const char* name);
  23. bool unregisterCreator(const ID& id);
  24. //bool unregisterAll();
  25. ID id(const char* name, bool caseSensitive = true) const;
  26. const char* name(const ID &id) const;
  27. size_t count() const;
  28. const std::vector<ID> &registeredIds() const;
  29. std::vector<const char*> registeredNames() const;
  30. Type* getRandom(); //remove
  31. // Type* at(int index);
  32. // ID idAt(int index);
  33.  
  34. protected:
  35. Factory() {}
  36. virtual ~Factory() {}
  37.  
  38. private:
  39. template<class C>
  40. static Type* create() {
  41. return new C();
  42. }
  43. typedef std::map<ID, Creator> CreatorMap;
  44. CreatorMap creators;
  45. std::vector<ID> ids;
  46. typedef std::map<ID, const char*> NameMap;
  47. NameMap name_map; //static?
  48. };

Factory 类继承了 Singleton ,这里就不展开说明 Singleton 了,只要知道这是一个单例模式的接口模板类,保证工厂只有一个实例,并且提供 Instance() 接口来获取实例。

再来看宏 FACTORY_DEFINE(T) 的定义:

  1. #define FACTORY_DEFINE(T) \
  2. class T##Factory : public Factory<T##Id, T, T##Factory> {}; \
  3. bool T::Register(T##Id id, T##Creator c, const char *name) { \
  4. DBG(#T "::Register(..., %s)\n", name); \
  5. return T##Factory::Instance().registerCreator(id, c) && T##Factory::Instance().registerIdName(id, name); \
  6. } \
  7. T* T::create(T##Id id) {return T##Factory::Instance().create(id);} \
  8. T* T::create(const char* name) { return T::create(T::id(name));} \
  9. T##Id* T::next(T##Id *id) { \
  10. const std::vector<T##Id>& ids = T##Factory::Instance().registeredIds(); \
  11. if (!id) return (T##Id*)&ids[]; \
  12. T##Id *id0 = (T##Id*)&ids[], *id1 = (T##Id*)&ids[ids.size() - ]; \
  13. if (id >= id0 && id < id1) return id + ; \
  14. if (id == id1) return NULL; \
  15. std::vector<T##Id>::const_iterator it = std::find(ids.begin(), ids.end(), *id); \
  16. if (it == ids.end()) return NULL; \
  17. return (T##Id*)&*(it++); \
  18. } \
  19. T##Id T::id(const char* name) { DBG(#T "::id(\"%s\")\n", name); return T##Factory::Instance().id(name, false);} \
  20. const char* T::name(T##Id id) {return T##Factory::Instance().name(id);}

下面以  FACTORY_DEFINE(VideoRenderer) 为例,展示这段宏展开之后的样子

  1. class VideoRendererFactory : public Factory<VideoRendererId, VideoRenderer, VideoRendererFactory> {};
  2. bool VideoRenderer::Register(VideoRendererId id, VideoRendererCreator c, const char *name) {
  3. DBG("VideoRenderer" "::Register(..., %s)n", name);
  4. return VideoRendererFactory::Instance().registerCreator(id, c) && VideoRendererFactory::Instance().registerIdName(id, name);
  5. }
  6. VideoRenderer* VideoRenderer::create(VideoRendererId id) {return VideoRendererFactory::Instance().create(id);}
  7. VideoRenderer* VideoRenderer::create(const char* name) { return VideoRenderer::create(VideoRenderer::id(name));}
  8. VideoRendererId* VideoRenderer::next(VideoRendererId *id) {
  9. const std::vector<VideoRendererId>& ids = VideoRendererFactory::Instance().registeredIds();
  10. if (!id) return (VideoRendererId*)&ids[];
  11. VideoRendererId *id0 = (VideoRendererId*)&ids[], *id1 = (VideoRendererId*)&ids[ids.size() - ];
  12. if (id >= id0 && id < id1) return id + ;
  13. if (id == id1) return NULL;
  14. std::vector<VideoRendererId>::const_iterator it = std::find(ids.begin(), ids.end(), *id);
  15. if (it == ids.end()) return NULL;
  16. return (VideoRendererId*)&*(it++);
  17. }
  18. VideoRendererId VideoRenderer::id(const char* name) { DBG("VideoRenderer" "::id("%s")n", name); return VideoRendererFactory::Instance().id(name, false);}
  19. const char* VideoRenderer::name(VideoRendererId id) {return VideoRendererFactory::Instance().name(id);}

可以看到,宏展开后,先定义 VideoRendererFactory 类,继承于 Factory ;

接下来,我们找到了 VideoRenderer 类的 private 域中声明的 VideoRenderer::Register 的定义。通过 VideoRendererFactory 的实例,分别绑定id和生成器以及id和名称;

后面的 create 方法则是通过 VideoRendererFactory 的实例得到 id 或 name 对应的产品类实例。

我们回过头来再看看 Fatory 是如何实现这些工厂函数的接口的:

  1. template<typename Id, typename T, class Class>
  2. typename Factory<Id, T, Class>::Type *Factory<Id, T, Class>::create(const ID& id)
  3. {
  4. typename CreatorMap::const_iterator it = creators.find(id);
  5. if (it == creators.end()) {
  6. DBG("Unknown id ");
  7. return ;
  8. //throw std::runtime_error(err_msg.arg(id).toStdString());
  9. }
  10. return (it->second)();
  11. }
  12.  
  13. template<typename Id, typename T, class Class>
  14. bool Factory<Id, T, Class>::registerCreator(const ID& id, const Creator& callback)
  15. {
  16. //DBG("%p id [%d] registered. size=%d\n", &Factory<Id, T, Class>::Instance(), id, ids.size());
  17. ids.insert(ids.end(), id);
  18. return creators.insert(typename CreatorMap::value_type(id, callback)).second;
  19. }
  20.  
  21. template<typename Id, typename T, class Class>
  22. bool Factory<Id, T, Class>::registerIdName(const ID& id, const char* name)
  23. {
  24. return name_map.insert(typename NameMap::value_type(id, name/*.toLower()*/)).second;
  25. }
  26.  
  27. template<typename Id, typename T, class Class>
  28. bool Factory<Id, T, Class>::unregisterCreator(const ID& id)
  29. {
  30. //DBG("Id [%d] unregistered\n", id);
  31. ids.erase(std::remove(ids.begin(), ids.end(), id), ids.end());
  32. name_map.erase(id);
  33. return creators.erase(id) == ;
  34. }
  35.  
  36. template<typename Id, typename T, class Class>
  37. typename Factory<Id, T, Class>::ID Factory<Id, T, Class>::id(const char* name, bool caseSensitive) const
  38. {
  39. #ifdef _MSC_VER
  40. #define strcasecmp(s1, s2) _strcmpi(s1, s2)
  41. #endif
  42. //need 'typename' because 'Factory<Id, T, Class>::NameMap' is a dependent scope
  43. for (typename NameMap::const_iterator it = name_map.begin(); it!=name_map.end(); ++it) {
  44. if (caseSensitive) {
  45. if (it->second == name || !strcmp(it->second, name))
  46. return it->first;
  47. } else {
  48. if (!strcasecmp(it->second, name)) {
  49. return it->first;
  50. }
  51. }
  52. }
  53. DBG("Not found\n");
  54. return ID(); //can not return ref. TODO: Use a ID wrapper class
  55. }
  56.  
  57. template<typename Id, typename T, class Class>
  58. const char* Factory<Id, T, Class>::name(const ID &id) const
  59. {
  60. typename NameMap::const_iterator it = name_map.find(id);
  61. if (it == name_map.end())
  62. return NULL;
  63. return it->second;
  64. }
  65.  
  66. template<typename Id, typename T, class Class>
  67. const std::vector<Id>& Factory<Id, T, Class>::registeredIds() const
  68. {
  69. return ids;
  70. }
  71.  
  72. template<typename Id, typename T, class Class>
  73. std::vector<const char*> Factory<Id, T, Class>::registeredNames() const
  74. {
  75. std::vector<const char*> names;
  76. for (typename NameMap::const_iterator it = name_map.begin(); it != name_map.end(); ++it) {
  77. names.push_back((*it).second);
  78. }
  79. return names;
  80. }
  81.  
  82. template<typename Id, typename T, class Class>
  83. size_t Factory<Id, T, Class>::count() const
  84. {
  85. //DBG("%p size = %d", &Factory<Id, T, Class>::Instance(), ids.size());
  86. return ids.size();
  87. }
  88.  
  89. template<typename Id, typename T, class Class>
  90. typename Factory<Id, T, Class>::Type* Factory<Id, T, Class>::getRandom()
  91. {
  92. srand(time());
  93. int index = rand() % ids.size();
  94. //DBG("random %d/%d", index, ids.size());
  95. ID new_eid = ids.at(index);
  96. //DBG("id %d", new_eid);
  97. return create(new_eid);
  98. }

维护每个产品的 ids Vector容器,id到创建器的映射,id到name的映射,create时,运行对应的创建器即可。

【QtAV】QtAV中的工厂模式的更多相关文章

  1. PHP中“简单工厂模式”实例讲解

    原创文章,转载请注明出处:http://www.cnblogs.com/hongfei/archive/2012/07/07/2580776.html 简单工厂模式:①抽象基类:类中定义抽象一些方法, ...

  2. JS中的工厂模式

    .一个栗子: var BicycleShop = function(){}; BicycleShop.prototype = { sellBicycle : function( model ){ va ...

  3. Spring中的工厂模式和单例模式

    Spring预备知识(适合中小型项目) 作用:集成和管理其他框架 工厂模式: A  a  = new A( ); 将类所要创建的对象写入工厂,统一进行管理 package com.spring; pu ...

  4. spring中的工厂模式

    spring的bean的创建原理就是框架利用反射创建出实例对象 工厂模式:工厂帮我们创建对象:有一个专门帮我们创建对象的类,我们把这个类叫做工厂类. 例如:Plane plane = PlaneFac ...

  5. PHP中“简单工厂模式”实例讲解(转)

      ? 1 2 3 4 5 6 7 8 原创文章,转载请注明出处:http://www.cnblogs.com/hongfei/archive/2012/07/07/2580776.html   简单 ...

  6. .Net Core 中使用工厂模式

    什么是工厂模式 工厂模式是最常用的设计模式之一,属于创建型模式. 有点: 解耦,可以把对象的创建和过程分开 减少代码量,易于维护 什么时候用? 当一个抽象类有多个实现的时候,需要多次实例化的时候,就要 ...

  7. c#中简单工厂模式

    运算类 public class yunsuan { public static operation create(string operate) { operation oper = null; s ...

  8. 设计模式(四)抽象工厂模式(Abstract Factory Pattern)

    一.引言 在上一专题中介绍了工厂方法模式,工厂方法模式是为了克服简单工厂模式的缺点而设计出来的,简单工厂模式的工厂类随着产品类的增加需要增加额外的代码,而工厂方法模式每个具体工厂类只完成单个实例的创建 ...

  9. 设计模式(二)简单工厂模式(Simple Factory Pattern)

    一.引言 这个系列也是自己对设计模式的一些学习笔记,希望对一些初学设计模式的人有所帮助的,在上一个专题中介绍了单例模式,在这个专题中继续为大家介绍一个比较容易理解的模式——简单工厂模式. 二.简单工厂 ...

随机推荐

  1. ios 微信发送位置

    @interface GroupReportViewController () <BMKMapViewDelegate,BMKLocationServiceDelegate,BMKGeoCode ...

  2. mysql 事件(Event) 总结

    1 事件简介 事件(event)是MySQL在相应的时刻调用的过程式数据库对象.一个事件可调用一次,也可周期性的启动,它由一个特定的线程来管理的,也就是所谓的“事件调度器”. 事件和触发器类似,都是在 ...

  3. bash rz 上传文件失败问题

    原文链接: https://blog.csdn.net/heavendai/article/details/7549065 单独用rz会有两个问题:上传中断.上传文件变化(md5不同), 解决办法是上 ...

  4. 51nod 1525 && CF566D

    题意:给定n个元素,现在有2种合并操作和1种询问操作 1.单独合并两个元素所在的集合 2.合并一个区间内的元素所在的集合 询问:两个元素是否属于统一集合 神犇题解 感觉又涨了新姿势啊..我们最恼火的是 ...

  5. An Assembly Language

    BUFFER OVERFLOW 3 An Assembly Language Introduction Basic of x86 Architecture Assembly Language Comp ...

  6. 大话设计模式--代理模式 proxy

    1. 代理模式: 为其他对象提供一种代理以控制这个对象的访问. 代理模式使用场合: a. 远程代理, 为一个对象在不同的地址空间提供局部代理,隐藏一个对象存在于不同地址空间的事实.如.net中WebS ...

  7. DIV+CSS IE6/IE7/IE8/FF兼容问题大全

    1. [代码][CSS]代码 1, FF下给 div 设置 padding 后会导致 width 和 height 增加, 但IE不会.(可用!important解决) 2, 居中问题. 1).垂直居 ...

  8. ListOperations

    RedisOperations<K,V> getOperations()  V index(K key, long index)  V leftPop(K key)  V leftPop( ...

  9. poj 2106 Boolean Expressions 课本代码

    #include<cstdio> const int maxn=100 +10; int val[maxn],vtop; int op[maxn],otop; void insert(in ...

  10. QTableWidget设计原则

    一.组成结构: 列表控件由水平表头(self.horizontalHeader()).垂直表头(self.verticalHeader())和单元格(QTableWidgetItem)组成 其中表头又 ...