【QtAV】QtAV中的工厂模式
阅读原文时间:2022年06月25日阅读:2

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

工厂模式的使用

以 VideoRenderer 类为例子,他含有下面3个工厂模式相关的方法,Register方法用于给一个产品注册其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(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(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 是这里定义的模板函数 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
class Factory : public Singleton
{
DISABLE_COPY(Factory)
typedef Id ID;
typedef T Type;
typedef Type* (*Creator)();
public:
Type* create(const ID& id);
template
bool register_(const ID& id) { // register_(id, name)
std::pair result = creators.insert(std::make_pair(id, create));
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
static Type* create() {
return new C();
}
typedef std::map CreatorMap;
CreatorMap creators;
std::vector ids;
typedef std::map NameMap;
NameMap name_map; //static?
};

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

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

#define FACTORY_DEFINE(T) \
class T##Factory : public Factory {}; \
bool T::Register(T##Id id, T##Creator c, const char *name) { \
DBG(#T "::Register(…, %s)\n", name); \
return T##Factory::Instance().registerCreator(id, c) && T##Factory::Instance().registerIdName(id, name); \
} \
T* T::create(T##Id id) {return T##Factory::Instance().create(id);} \
T* T::create(const char* name) { return T::create(T::id(name));} \
T##Id* T::next(T##Id *id) { \
const std::vector& ids = T##Factory::Instance().registeredIds(); \
if (!id) return (T##Id*)&ids[]; \
T##Id *id0 = (T##Id*)&ids[], *id1 = (T##Id*)&ids[ids.size() - ]; \
if (id >= id0 && id < id1) return id + ; \ if (id == id1) return NULL; \ std::vector::const_iterator it = std::find(ids.begin(), ids.end(), *id); \
if (it == ids.end()) return NULL; \
return (T##Id*)&*(it++); \
} \
T##Id T::id(const char* name) { DBG(#T "::id(\"%s\")\n", name); return T##Factory::Instance().id(name, false);} \
const char* T::name(T##Id id) {return T##Factory::Instance().name(id);}

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

 class VideoRendererFactory : public Factory<VideoRendererId, VideoRenderer, VideoRendererFactory> {};  
 bool VideoRenderer::Register(VideoRendererId id, VideoRendererCreator c, const char \*name) {  
     DBG("VideoRenderer" "::Register(..., %s)n", name);  
     return VideoRendererFactory::Instance().registerCreator(id, c) && VideoRendererFactory::Instance().registerIdName(id, name);  
 }  
 VideoRenderer\* VideoRenderer::create(VideoRendererId id) {return VideoRendererFactory::Instance().create(id);}  
 VideoRenderer\* VideoRenderer::create(const char\* name) { return VideoRenderer::create(VideoRenderer::id(name));}  
 VideoRendererId\* VideoRenderer::next(VideoRendererId \*id) {  
     const std::vector<VideoRendererId>& ids = VideoRendererFactory::Instance().registeredIds();  
     if (!id) return (VideoRendererId\*)&ids\[\];  
     VideoRendererId \*id0 = (VideoRendererId\*)&ids\[\], \*id1 = (VideoRendererId\*)&ids\[ids.size() - \];  
     if (id >= id0 && id < id1) return id + ;  
     if (id == id1) return NULL;  
     std::vector<VideoRendererId>::const\_iterator it = std::find(ids.begin(), ids.end(), \*id);  
     if (it == ids.end()) return NULL;  
     return (VideoRendererId\*)&\*(it++);  
 }  
 VideoRendererId VideoRenderer::id(const char\* name) { DBG("VideoRenderer" "::id("%s")n", name); return VideoRendererFactory::Instance().id(name, false);}  
 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 Factory::Type *Factory::create(const ID& id)
{
typename CreatorMap::const_iterator it = creators.find(id);
if (it == creators.end()) {
DBG("Unknown id ");
return ;
//throw std::runtime_error(err_msg.arg(id).toStdString());
}
return (it->second)();
}

template
bool Factory::registerCreator(const ID& id, const Creator& callback)
{
//DBG("%p id [%d] registered. size=%d\n", &Factory::Instance(), id, ids.size());
ids.insert(ids.end(), id);
return creators.insert(typename CreatorMap::value_type(id, callback)).second;
}

template
bool Factory::registerIdName(const ID& id, const char* name)
{
return name_map.insert(typename NameMap::value_type(id, name/*.toLower()*/)).second;
}

template
bool Factory::unregisterCreator(const ID& id)
{
//DBG("Id [%d] unregistered\n", id);
ids.erase(std::remove(ids.begin(), ids.end(), id), ids.end());
name_map.erase(id);
return creators.erase(id) == ;
}

template
typename Factory::ID Factory::id(const char* name, bool caseSensitive) const
{
#ifdef _MSC_VER
#define strcasecmp(s1, s2) _strcmpi(s1, s2)
#endif
//need 'typename' because 'Factory::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\n");
return ID(); //can not return ref. TODO: Use a ID wrapper class
}

template
const char* Factory::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
const std::vector& Factory::registeredIds() const
{
return ids;
}

template
std::vector Factory::registeredNames() const
{
std::vector names;
for (typename NameMap::const_iterator it = name_map.begin(); it != name_map.end(); ++it) {
names.push_back((*it).second);
}
return names;
}

template
size_t Factory::count() const
{
//DBG("%p size = %d", &Factory::Instance(), ids.size());
return ids.size();
}

template
typename Factory::Type* Factory::getRandom()
{
srand(time());
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时,运行对应的创建器即可。