一般而言,当我们使用工厂模式时,通常这么使用:
举例示例 1
renderer.h
#ifndef RENDERER_H
#define RENDERER_H
#include <string>
// An abstract interface for a 3D renderer.
class IRenderer {
public:
virtual ~IRenderer() {}
virtual bool LoadScene(const std::string &filename) = 0;
virtual void SetViewportSize(int w, int h) = 0;
virtual void SetCameraPos(double x, double y, double z) = 0;
virtual void SetLookAt(double x, double y, double z) = 0;
virtual void Render() = 0;
};
#endif
rendererfactory.h
#ifndef RENDERERFACTORY_H
#define RENDERERFACTORY_H
#include "renderer.h"
#include <string>
// A factory object that creates instances of different 3D renderers.
class RendererFactory {
public:
// Create a new instance of a named 3D renderer.
// type can be one of "opengl", "directx", or "mesa"
IRenderer *CreateRenderer(const std::string &type);
};
#endif
rendererfactory.cpp
#include "rendererfactory.h"
#include <iostream>
using std::cout;
using std::endl;
class OpenGLRenderer : public IRenderer {
public:
~OpenGLRenderer() {}
bool LoadScene(const std::string &filename) { return true; }
void SetViewportSize(int w, int h) {}
void SetCameraPos(double x, double y, double z) {}
void SetLookAt(double x, double y, double z) {}
void Render() { cout << "OpenGL Render" << endl; }
};
class DirectXRenderer : public IRenderer {
public:
bool LoadScene(const std::string &filename) { return true; }
void SetViewportSize(int w, int h) {}
void SetCameraPos(double x, double y, double z) {}
void SetLookAt(double x, double y, double z) {}
void Render() { cout << "DirectX Render" << endl; }
};
class MesaRenderer : public IRenderer {
public:
bool LoadScene(const std::string &filename) { return true; }
void SetViewportSize(int w, int h) {}
void SetCameraPos(double x, double y, double z) {}
void SetLookAt(double x, double y, double z) {}
void Render() { cout << "Mesa Render" << endl; }
};
IRenderer *RendererFactory::CreateRenderer(const std::string &type)
{
if (type == "opengl") {
return new OpenGLRenderer;
}
if (type == "directx") {
return new DirectXRenderer;
}
if (type == "mesa") {
return new MesaRenderer;
}
return nullptr;
}
main.cpp
#include "rendererfactory.h"
int main(int, char **)
{
// create the factory object
RendererFactory *f = new RendererFactory;
// create an OpenGL renderer
IRenderer *ogl = f->CreateRenderer("opengl");
ogl->Render();
delete ogl;
// create a Mesa software renderer
IRenderer *mesa = f->CreateRenderer("mesa");
mesa->Render();
delete mesa;
delete f;
return 0;
}
当在模块内运行时,这么使用,是没有问题的。但当抽象出作为SDK发布给用户做二次开发使用,用户是感知不到.cpp
文件的,这些不随 SDK(api)发布给用户使用,用户感知不到不同渲染器的私有细节,看不到不同渲染器的具体类型,用户只能通过字符串变量指定渲染器。
这个时候,如果想为系统添加新的渲染器是做不到的。这就需要将具体的派生类和工厂方法解耦,并支持在运行时添加新的派生类。可以采用如下方法进行:
让工厂类维护一个映射,此映射将类型名和创建对象的回调关联起来,然后就可以允许新的派生类通过一对新的方法调用来实现注册和注销。运行时注册新类的能力,允许工厂方法模式为 API 创建可扩展性的插件接口。
举例示例 2
renderer.h
#ifndef RENDERER_H
#define RENDERER_H
#include <string>
// An abstract interface for a 3D renderer.
class IRenderer {
public:
virtual ~IRenderer() {}
virtual bool LoadScene(const std::string &filename) = 0;
virtual void SetViewportSize(int w, int h) = 0;
virtual void SetCameraPos(double x, double y, double z) = 0;
virtual void SetLookAt(double x, double y, double z) = 0;
virtual void Render() = 0;
virtual IRenderer *Create() = 0;
};
#endif
rendererfactory.h
#ifndef RENDERERFACTORY_H
#define RENDERERFACTORY_H
#include "renderer.h"
#include <string>
#include <map>
// A factory object that creates instances of different
// 3D renderers. New renderers can be dynamically added
// and removed from the factory object.
class RendererFactory {
public:
// The type for the callback that creates an IRenderer instance
typedef IRenderer* (*CreateCallback)();
// Add a new 3D renderer to the system
static void RegisterRenderer(const std::string &type, CreateCallback cb);
// Remove an existing 3D renderer from the system
static void UnregisterRenderer(const std::string &type);
// Create an instance of a named 3D renderer
static IRenderer *CreateRenderer(const std::string &type);
private:
typedef std::map<std::string, CreateCallback> CallbackMap;
static CallbackMap mRenderers;
};
#endif
rendererfactory.cpp
#include "rendererfactory.h"
#include <iostream>
// instantiate the static variable in RendererFactory
RendererFactory::CallbackMap RendererFactory::mRenderers;
void RendererFactory::RegisterRenderer(const std::string &type, CreateCallback cb)
{
mRenderers[type] = cb;
}
void RendererFactory::UnregisterRenderer(const std::string &type)
{
mRenderers.erase(type);
}
IRenderer *RendererFactory::CreateRenderer(const std::string &type)
{
CallbackMap::iterator it = mRenderers.find(type);
if (it != mRenderers.end()) {
// call the creation callback to construct this derived type
return (it->second)();
}
return nullptr;
}
main.cpp
#include "rendererfactory.h"
#include <iostream>
using std::cout;
using std::endl;
// An OpenGL-based 3D renderer
class OpenGLRenderer : public IRenderer
{
public:
~OpenGLRenderer() {}
bool LoadScene(const std::string &filename) { return true; }
void SetViewportSize(int w, int h) {}
void SetCameraPos(double x, double y, double z) {}
void SetLookAt(double x, double y, double z) {}
void Render() { cout << "OpenGL Render" << endl; }
IRenderer *Create() { return new OpenGLRenderer; }
};
// A DirectX-based 3D renderer
class DirectXRenderer : public IRenderer
{
public:
bool LoadScene(const std::string &filename) { return true; }
void SetViewportSize(int w, int h) {}
void SetCameraPos(double x, double y, double z) {}
void SetLookAt(double x, double y, double z) {}
void Render() { cout << "DirectX Render" << endl; }
IRenderer *Create() { return new DirectXRenderer; }
};
// A Mesa-based software 3D renderer
class MesaRenderer : public IRenderer
{
public:
bool LoadScene(const std::string &filename) { return true; }
void SetViewportSize(int w, int h) {}
void SetCameraPos(double x, double y, double z) {}
void SetLookAt(double x, double y, double z) {}
void Render() { cout << "Mesa Render" << endl; }
IRenderer *Create() { return new MesaRenderer; }
};
int main(int, char **)
{
// register the various 3D renderers with the factory object
RendererFactory::RegisterRenderer("opengl", OpenGLRenderer::Create);
RendererFactory::RegisterRenderer("directx", DirectXRenderer::Create);
RendererFactory::RegisterRenderer("mesa", MesaRenderer::Create);
// create an OpenGL renderer
IRenderer *ogl = RendererFactory::CreateRenderer("opengl");
ogl->Render();
delete ogl;
// create a Mesa software renderer
IRenderer *mesa = RendererFactory::CreateRenderer("mesa");
mesa->Render();
delete mesa;
// unregister the Mesa renderer
RendererFactory::UnregisterRenderer("mesa");
mesa = RendererFactory::CreateRenderer("mesa");
if (! mesa)
{
cout << "Mesa renderer unregistered" << endl;
}
return 0;
}