zoukankan      html  css  js  c++  java
  • 【QtAV】QtAV中的工厂模式

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

    工厂模式的使用

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

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

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

    注册

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

    生产一个Direct2DRenderer实例

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

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

    工厂模式的实现过程

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

    // Direct2DRenderer 和 VideoRendererDirect2D 是等价的
    typedef Direct2DRenderer VideoRendererDirect2D;

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

    void registerRenderers()

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

    extern void RegisterVideoRendererDirect2D_Man();

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

    void RegisterVideoRendererDirect2D_Man()
    {
        VideoRenderer::Register<Direct2DRenderer>(VideoRendererId_Direct2D, "Direct2D");
    }

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

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

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

        template<class C>
        static VideoRenderer* create() {
            return new C();
        }
        typedef VideoRenderer* (*VideoRendererCreator)();
        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 文件中找到:

    FACTORY_DEFINE(VideoRenderer)

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

    /*
     * Used in library, can not be used both in library and outside. so we don't need export it
     */
    
    template <typename Id, typename T, class Class>
    class Factory : public Singleton<Class>
    {
        DISABLE_COPY(Factory)
        typedef Id ID;
        typedef T Type;
        typedef Type* (*Creator)();
    public:
        Type* create(const ID& id);
        template<class C>
        bool register_(const ID& id) { // register_<C>(id, name)
            std::pair<typename CreatorMap::iterator, bool> result = creators.insert(std::make_pair(id, create<C>));
            return result.second;
        }
    
        //template <typename Func>
        bool registerCreator(const ID& id, const Creator& callback);
        bool registerIdName(const ID& id, const char* name);
        bool unregisterCreator(const ID& id);
        //bool unregisterAll();
        ID id(const char* name, bool caseSensitive = true) const;
        const char* name(const ID &id) const;
        size_t count() const;
        const std::vector<ID> &registeredIds() const;
        std::vector<const char*> registeredNames() const;
        Type* getRandom(); //remove
    //    Type* at(int index);
    //    ID idAt(int index);
    
    protected:
        Factory() {}
        virtual ~Factory() {}
    
    private:
        template<class C>
        static Type* create() {
            return new C();
        }
        typedef std::map<ID, Creator> CreatorMap;
        CreatorMap creators;
        std::vector<ID> ids;
        typedef std::map<ID, const char*> NameMap;
        NameMap name_map; //static?
    };

    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)
    ", 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[0]; 
    12         T##Id *id0 = (T##Id*)&ids[0], *id1 = (T##Id*)&ids[ids.size() - 1]; 
    13         if (id >= id0 && id < id1) return id + 1; 
    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")
    ", 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[0]; 
    11         VideoRendererId *id0 = (VideoRendererId*)&ids[0], *id1 = (VideoRendererId*)&ids[ids.size() - 1]; 
    12         if (id >= id0 && id < id1) return id + 1; 
    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 是如何实现这些工厂函数的接口的:

    template<typename Id, typename T, class Class>
    typename Factory<Id, T, Class>::Type *Factory<Id, T, Class>::create(const ID& id)
    {
        typename CreatorMap::const_iterator it = creators.find(id);
        if (it == creators.end()) {
            DBG("Unknown id ");
            return 0;
            //throw std::runtime_error(err_msg.arg(id).toStdString());
        }
        return (it->second)();
    }
    
    template<typename Id, typename T, class Class>
    bool Factory<Id, T, Class>::registerCreator(const ID& id, const Creator& callback)
    {
        //DBG("%p id [%d] registered. size=%d
    ", &Factory<Id, T, Class>::Instance(), id, ids.size());
        ids.insert(ids.end(), id);
        return creators.insert(typename CreatorMap::value_type(id, callback)).second;
    }
    
    template<typename Id, typename T, class Class>
    bool Factory<Id, T, Class>::registerIdName(const ID& id, const char* name)
    {
        return name_map.insert(typename NameMap::value_type(id, name/*.toLower()*/)).second;
    }
    
    template<typename Id, typename T, class Class>
    bool Factory<Id, T, Class>::unregisterCreator(const ID& id)
    {
        //DBG("Id [%d] unregistered
    ", id);
        ids.erase(std::remove(ids.begin(), ids.end(), id), ids.end());
        name_map.erase(id);
        return creators.erase(id) == 1;
    }
    
    template<typename Id, typename T, class Class>
    typename Factory<Id, T, Class>::ID Factory<Id, T, Class>::id(const char* name, bool caseSensitive) const
    {
    #ifdef _MSC_VER
    #define strcasecmp(s1, s2) _strcmpi(s1, s2)
    #endif
        //need 'typename'  because 'Factory<Id, T, Class>::NameMap' is a dependent scope
        for (typename NameMap::const_iterator it = name_map.begin(); it!=name_map.end(); ++it) {
            if (caseSensitive) {
                if (it->second == name || !strcmp(it->second, name))
                    return it->first;
            } else {
                if (!strcasecmp(it->second, name)) {
                    return it->first;
                }
            }
        }
        DBG("Not found
    ");
        return ID(); //can not return ref. TODO: Use a ID wrapper class
    }
    
    template<typename Id, typename T, class Class>
    const char* Factory<Id, T, Class>::name(const ID &id) const
    {
        typename NameMap::const_iterator it = name_map.find(id);
        if (it == name_map.end())
            return NULL;
        return it->second;
    }
    
    template<typename Id, typename T, class Class>
    const std::vector<Id>& Factory<Id, T, Class>::registeredIds() const
    {
        return ids;
    }
    
    template<typename Id, typename T, class Class>
    std::vector<const char*> Factory<Id, T, Class>::registeredNames() const
    {
        std::vector<const char*> names;
        for (typename NameMap::const_iterator it = name_map.begin(); it != name_map.end(); ++it) {
            names.push_back((*it).second);
        }
        return names;
    }
    
    template<typename Id, typename T, class Class>
    size_t Factory<Id, T, Class>::count() const
    {
        //DBG("%p size = %d", &Factory<Id, T, Class>::Instance(), ids.size());
        return ids.size();
    }
    
    template<typename Id, typename T, class Class>
    typename Factory<Id, T, Class>::Type* Factory<Id, T, Class>::getRandom()
    {
        srand(time(0));
        int index = rand() % ids.size();
        //DBG("random %d/%d", index, ids.size());
        ID new_eid = ids.at(index);
        //DBG("id %d", new_eid);
        return create(new_eid);
    }

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

  • 相关阅读:
    异或和之和
    Wannafly挑战赛19C:多彩的树
    HDU 6035 树形dp
    利用C++套接字发送邮件
    洛谷P3368树状模板(区间更新+单点查询+差分)
    CCF 201903-1 小中大
    关于树状数组
    CODEVS 4189 (前缀是否出现)
    关于字典树
    hdu 1022 Train Problem
  • 原文地址:https://www.cnblogs.com/pplxlee/p/11051147.html
Copyright © 2011-2022 走看看