文章目錄
- 抽象基類、工廠方法
- 擴展工廠
抽象基類、工廠方法
renderer.h
#ifndef UNTITLED_RENDERER_H
#define UNTITLED_RENDERER_H#include <string>
class IRenderer {
public:virtual ~IRenderer() {}virtual bool func1(const std::string& filename) = 0;virtual void Render() = 0;
};
#endif //UNTITLED_RENDERER_H
rendererfactory.h
#ifndef UNTITLED_RENDERERFACTORY_H
#define UNTITLED_RENDERERFACTORY_H
#include "renderer.h"
#include "string"
class RendererFactory {
public:IRenderer* CreateRenderer(const std::string& type); // 返回派生類對象實例
};
#endif //UNTITLED_RENDERERFACTORY_H
rendererfactory.cpp
#include "rendererfactory.h"
#include 其他派生類的.h
//IRenderer* Render
IRenderer *RendererFactory::CreateRenderer(const std::string &type) {if (type == "opengl") {return new OpenGlRenderer();} else if (type == "directx") {return new DirectxRenderer();} else {return new MesaRenderer();}return NULL;
}
工廠方法能夠返回IRenderer
的3個派生類的任意一個,取決于輸入字符串,這意味著能夠基于用戶輸入或根據運行時讀入的配置文件創建不同的類。各個派生類的頭文件為私有頭文件,僅僅包含在工廠.cpp中,不需要隨著API一起發布。
該方法的缺點:
包含了可用的派生類的硬編碼信息,若需要為系統添加新的渲染器,則必須修改rendererfactory.cpp
擴展工廠
為了將具體的派生類你和工廠方法解耦,并支持在運行時添加新的派生類,可以這樣修改工廠類:
1、工廠類維護一個銀蛇,將類型名與創建對象的回調關聯起來
2、允許新的派生類以一對新的方法調用來實現注冊和注銷
3、運行時注冊新類的能力允許工廠方法為API創建可以擴展的插件接口
4、工廠對象必須保存狀態信息,因此最好強制要求任意時刻只能創建一個工廠對象,簡潔起見,使用靜態方法/變量實現
rendererfactory.h
//
// Created by hanhandi on 2022/8/18.
//#ifndef UNTITLED_RENDERERFACTORY_H
#define UNTITLED_RENDERERFACTORY_H
#include "renderer.h"
#include "string"
#include "map"class RendererFactory {
public:
// IRenderer* CreateRenderer(const std::string& type); // 返回派生類對象實例typedef IRenderer* (*CreateCallback) ();static void RegisterRender(const std::string& type, CreateCallback cb);static void UnregisterRender(const std::string& type);static IRenderer* CreateRender(const std::string& type);
private:typedef std::map<std::string, CreateCallback> CallbackMap;static CallbackMap mRenderers;
};
#endif //UNTITLED_RENDERERFACTORY_H
rendererfactory.cpp
//
// Created by hanhandi on 2022/8/18.
//
#include "rendererfactory.h"// 在RendererFactory 中實例化靜態變量
RendererFactory::CallbackMap RendererFactory::mRenderers;void RendererFactory::RegisterRender(const std::string &type, CreateCallback cb) {mRenderers[type] = cb;
}void RendererFactory::UnregisterRender(const std::string &type) {mRenderers.erase(type);
}IRenderer *RendererFactory::CreateRender(const std::string &type) {CallbackMap::iterator it = mRenderers.find(type);if (it != mRenderers.end()) {// 調用回調以構造此派生類型的對象return (it->second)();}return NULL;
}
在main函數中我們進行新類的注冊:
main.cpp
#include <iostream>
#include "rendererfactory.h"class UserRenderer : public IRenderer
{
public:~UserRenderer() {}bool func1(const std::string& filename) { return true; }void Render() { }static IRenderer* Create() { return new UserRenderer(); }
};
int main() {// 注冊一個新的渲染器RendererFactory::RegisterRender("user", UserRenderer::Create);// 為新渲染器創建實例IRenderer* r = RendererFactory::CreateRender("user");r->Render();delete r;std::cout << "Hello, World!" << std::endl;return 0;
}
主要注意的地方:
static IRenderer* Create() { return new UserRenderer(); }
是新類新添加的函數,在工廠的注冊函數中需要接受返回對象的回調。