青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品

woaidongmao

文章均收錄自他人博客,但不喜標(biāo)題前加-[轉(zhuǎn)貼],因其丑陋,見諒!~
隨筆 - 1469, 文章 - 0, 評論 - 661, 引用 - 0
數(shù)據(jù)加載中……

用C++實現(xiàn)插件體系結(jié)構(gòu)

本文討論一種簡單卻有效的插件體系結(jié)構(gòu),它使用C++,動態(tài)鏈接庫,基于面向?qū)ο缶幊痰乃枷搿?span lang="EN-US">
首先來看一下使用插件機制能給我們帶來哪些方面的好處,從而在適當(dāng)時候合理的選擇使用。
1
, 增強代碼的透明度與一致性:因為插件通常會封裝第三方類庫或是其他人編寫的代碼,需要清晰地定義出接口,用清晰一致的接口來面對所有事情。你的代碼也不會被轉(zhuǎn)換程序或是庫的特殊定制需求弄得亂七糟。
2
, 
改善工程的模塊化:你的代碼被清析地分成多個獨立的模塊,可以把它們安置在子工程中的文件組中。這種解耦處理使得創(chuàng)建出的組件更加容易重用。
3
 
更短的編譯時間:如果僅僅是為了解釋某些類的聲明,而這些類內(nèi)部使用了外部庫,編譯器不再需要解析外部庫的頭文件了,因為具體實現(xiàn)是以私有的形式完成。
4
, 
更換與增加組件:假如你需要向用戶發(fā)布補丁,那么更新單獨的插件而不是替代每一個安裝了的文件更為有效。當(dāng)使用新的渲染器或是新的單元類型來擴展你的游戲時,能過向引擎提供一組插件,可以很容易的實現(xiàn)。
5
, 
在關(guān)閉源代碼的工程中使用GPL代碼:一般,假如你使用了GPL發(fā)布的代碼,那么你也需要開放你的源代碼。然而,如果把GPL組件封裝在插件中,你就不必發(fā)布插件的源碼。

介紹
先簡單解釋一下什么是插件系統(tǒng)以及它如何工作:在普通的程序中,假如你需要代碼執(zhí)行一項特殊的任務(wù),你有兩種選擇:要么你自己編寫,要么你尋找一個已經(jīng)存在的滿足你需要的庫。現(xiàn)在,你的要求變了,那你只好重寫代碼或是尋找另一個不同的庫。無論是哪種方式,都會導(dǎo)致你框架代碼中的那些依賴外部庫的代碼重寫。
現(xiàn)在,我們可以有另外一種選擇:在插件系統(tǒng)中,工程中的任何組件不再束縛于一種特定的實現(xiàn)(像渲染器既可以基于OpenGL,也可以選擇Direct3D,它們會從框架代碼中剝離出來,通過特定的方法被放入動態(tài)鏈接庫之中。
所謂的特定方法包括在框架代碼中創(chuàng)建接口,這些接口使得框架與動態(tài)庫解耦。插件提供接口的實現(xiàn)。我們把插件與普通的動態(tài)鏈接庫區(qū)分開來是因為它們的加載方式不同:程序不會直接鏈接插件,而可能是在某些目錄下查找,如果發(fā)現(xiàn)便進行加載。所有插件都可以使用一種共同的方法與應(yīng)用進行聯(lián)結(jié)。

常見的錯誤
一些程序員,當(dāng)進行插件系統(tǒng)的設(shè)計時,可能會給每一個作為插件使用的動態(tài)庫添加一個如下函數(shù)類似的函數(shù):PluginClass *createInstance(const char*);
然后它們讓插件去提供一些類的實現(xiàn)。引擎用期望的對象名對加載的插件逐個進行查詢,直到某個插件返回,這是典型的設(shè)計模式中職責(zé)鏈模式的做法。一些更聰明的程序員會做出新的設(shè)計,使插件在引擎中注冊自己,或是用定制的實現(xiàn)替代引擎內(nèi)部缺省實現(xiàn):
Void dllStartPlugin(PluginManager &pm);
Void dllStopPlugin(PluginManager &pm);
第一種設(shè)計的主要問題是:插件工廠創(chuàng)建的對象需要使用reinterpret_cast<>來進行轉(zhuǎn)換。通常,插件從共同基類(這里指PluginClass)派生,會引用一些不安全的感覺。實際上,這樣做也是沒意義的,插件應(yīng)該默默地響應(yīng)輸入設(shè)備的請求,然后提交結(jié)果給輸出設(shè)備。
在這種結(jié)構(gòu)下,為了提供相同接口的多個不同實現(xiàn),需要的工作變得異常復(fù)雜,如果插件可以用不同名字注冊自己(如Direct3DRenderer and OpenGLRenderer,但是引擎不知道哪個具體實現(xiàn)對用戶的選擇是有效的。假如把所有可能的實現(xiàn)列表硬編碼到程序中,那么使用插件結(jié)構(gòu)的目的也沒有意義了。
假如插件系統(tǒng)通過一個框架或是庫(如游戲引擎) 實現(xiàn),架構(gòu)師也肯定會把功能暴露給應(yīng)用程序使用。這樣,會帶來一些問題像如何在應(yīng)用程序中使用插件,插件作者如何引擎的頭文件等,這包含了潛在的三者之間版本沖突的可能性。
單獨的工廠
接口,是被引擎清楚定義的,而不是插件。引擎通過定義接口來指導(dǎo)插件做什么工作,插件具體實現(xiàn)功能。我們讓插件注冊自己的引擎接口的特殊實現(xiàn)。當(dāng)然直接創(chuàng)建插件實現(xiàn)類的實例并注冊是比較笨的做法。這樣使得同一時刻所有可能的實現(xiàn)同時存在,占用內(nèi)存與CPU資源。解決的辦法是工廠類,它唯一的目的是在請求時創(chuàng)建另外類的實例。如果引擎定義了接口與插件通信,那么也應(yīng)該為工廠類定義接口:
template<typename Interface>
class Factory {
 
virtual Interface *create() = 0;
};
 
class Renderer {
 
virtual void beginScene() = 0;
 
virtual void endScene() = 0;
};
typedef Factory<Renderer> RendererFactory;

選擇1: 插件管理器
接下來應(yīng)該考慮插件如何在引擎中注冊它們的工廠,引擎又如何實際地使用這些注冊的插件。一種選擇是與存在的代碼很好的接合,這通過寫插件管理器來完成。這使得我們可以控制哪些組件允許被擴展。
class PluginManager {
 
void registerRenderer(std::auto_ptr<RendererFactory> RF);
 
void registerSceneManager(std::auto_ptr<SceneManagerFactory> SMF);
};
當(dāng)引擎需要一個渲染器時,它會訪問插件管理器,看哪些渲染器已經(jīng)通過插件注冊了。然后要求插件管理器創(chuàng)建期望的渲染器,插件管理器于是使用工廠類來生成渲染器,插件管理器甚至不需要知道實現(xiàn)細節(jié)。
插件由動態(tài)庫組成,后者導(dǎo)出一個可以被插件管理器調(diào)用的函數(shù),用以注冊自己:
void registerPlugin(PluginManager &PM);
插件管理器簡單地在特定目錄下加載所有dll文件,檢查它們是否有一個名為registerPlugin()的導(dǎo)出函數(shù)。當(dāng)然也可用xml文檔來指定哪些插件要被加載。 

選擇 2: 完整地集成Fully Integrated
除了使用插件管理器,也可以從頭設(shè)計代碼框架以支持插件。最好的方法是把引擎分成幾個子系統(tǒng),構(gòu)建一個系統(tǒng)核心來管理這些子系統(tǒng)。可能像下面這樣:

class Kernel {
  StorageServer &getStorageServer() const;
  GraphicsServer &getGraphicsServer() const;
};
 
class StorageServer {
  //提供給插件使用,注冊新的讀檔器
  void addArchiveReader(std::auto_ptr<ArchiveReader> AL);
 
// 查詢所有注冊的讀檔器,直到找到可以打開指定格式的讀檔器
  std::auto_ptr<Archive> openArchive(const std::string &sFilename);
};
 
class GraphicsServer {
 
// 供插件使用,用來添加驅(qū)動
  void addGraphicsDriver(std::auto_ptr<GraphicsDriver> AF);
 
 
// 獲取有效圖形驅(qū)動的數(shù)目
  size_t getDriverCount() const;
//返回驅(qū)動
  GraphicsDriver &getDriver(size_t Index);
};
這里有兩個子系統(tǒng),它們使用” Server”作為后綴。第一個Server內(nèi)部維護一個有效圖像加載器的列表,每次當(dāng)用戶希望加載一幅圖片時,圖像加載器被一一查詢,直到發(fā)現(xiàn)一個特定的實現(xiàn)可以處理特定格式的圖片。另一個子系統(tǒng)有一個GraphicsDrivers的列表,它們作為Renderers的工廠來使用。可以是Direct3DgraphicsDriver或是OpenGLGraphicsDrivers,它們分別負責(zé)Direct3DrendererOpenGLRenderer的創(chuàng)建。引擎提供有效的驅(qū)動列表供用戶選擇使用,通過安裝一個新的插件,新的驅(qū)動也可以被加入。

版本
在上面兩個可選擇的方法中,不強制要求你把特定的實現(xiàn)放到插件中。假如你的引擎提供一個讀檔器的默認實現(xiàn),以支持自定義文件包格式。你可以把它放到引擎本身,當(dāng)StorageServer 啟動時自動進行注冊。
現(xiàn)在還有一個問題沒有討論:假如你不小心的話,與引擎不匹配(例如,已經(jīng)過時的)插件會被加載。子系統(tǒng)類的一些變化或是插件管理器的改變足以導(dǎo)致內(nèi)存布局的改變,當(dāng)不匹配的插件試圖注冊時可能發(fā)生沖突甚至崩潰。比較討厭的是,這些在調(diào)試時難與發(fā)現(xiàn)。幸運的是,辨認過時或不正確的插件非常容易。最可靠的是方法是在你的核心系統(tǒng)中放置一個預(yù)處理常量。任何插件都有一個函數(shù),它可以返回這個常量給引擎:
// Somewhere in your core system
#define MyEngineVersion 1;
 
// The plugin
extern int getExpectedEngineVersion() {
  return MyEngineVersion;
}
在這個常量被編譯到插件后,當(dāng)引擎中的常量改變時,任何沒有進行重新編譯的插件它的 getExpectedEngineVersion ()方法會返回以前的那個值。引擎可以根據(jù)這個值,拒絕加載不匹配的插件。為了使插件可以重新工作,必須重新編譯它。當(dāng)然,最大的危險是你忘記了更新常量值。無論如何,你應(yīng)該有個自動版本管理工具幫助你。

 英文原文地址:http://www.nuclex.org/articles/building-a-better-plugin-architecture
 
有示例代碼下載

 

posted on 2009-09-02 22:01 肥仔 閱讀(488) 評論(0)  編輯 收藏 引用 所屬分類: 編程思想

青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品
  • <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>
            尤物yw午夜国产精品视频| 亚洲欧美日韩一区二区| 久久久999| 欧美有码视频| 欧美一区=区| 亚洲精品日韩欧美| 久久福利精品| 正在播放亚洲一区| 欧美激情bt| 欧美一级淫片播放口| 欧美激情按摩在线| 日韩午夜精品视频| 亚洲国产日韩综合一区| 另类天堂视频在线观看| 久久久五月婷婷| 国产欧美日韩综合一区在线播放| 欧美a级片网| 欧美成人免费网站| 在线视频日韩| 久久精品国产亚洲5555| 欧美日韩亚洲一区二区| 亚洲精品美女在线观看播放| 韩国在线视频一区| 欧美ed2k| 日韩午夜中文字幕| 美日韩精品免费观看视频| 久久精品视频免费观看| 欧美成人午夜激情视频| 91久久精品网| 亚洲国产黄色| 国产主播精品在线| 欧美va亚洲va日韩∨a综合色| 乱码第一页成人| 亚洲欧美日韩一区二区| 久久天天躁狠狠躁夜夜爽蜜月| 亚洲国产日韩欧美在线动漫| 亚洲欧美激情四射在线日| 欧美丰满高潮xxxx喷水动漫| 国产专区欧美精品| 欧美在线观看一区二区| 老司机精品福利视频| 国产精品视频一二三| 国产精品蜜臀在线观看| 亚洲午夜成aⅴ人片| 欧美黄色免费网站| 艳女tv在线观看国产一区| 久久久久久9999| 最近看过的日韩成人| 国产日韩精品一区| 国产精品日本| 亚洲人成在线播放网站岛国| 久久国产精品色婷婷| 正在播放亚洲| 国产精品日韩| 欧美一区精品| 久久久久久尹人网香蕉| 狠狠色综合网| 久久久久久91香蕉国产| 欧美亚洲综合久久| 极品尤物久久久av免费看| 久久天堂精品| 性欧美超级视频| 精品999在线播放| 91久久精品美女高潮| 欧美日韩国产一区精品一区 | 欧美激情综合在线| 久久综合中文色婷婷| 亚洲一二三四区| 亚久久调教视频| 久久综合一区二区三区| 欧美在线播放| 午夜久久福利| 中国成人黄色视屏| 亚洲一区二区三区国产| 一区免费观看视频| 亚洲欧美日韩在线| 亚洲欧美一区二区在线观看| 亚洲午夜免费福利视频| 在线天堂一区av电影| 韩国av一区| 亚洲福利视频二区| 久久久欧美一区二区| 99精品视频免费全部在线| 日韩视频免费观看高清完整版| 亚洲精品激情| 免费视频一区二区三区在线观看| 欧美福利一区二区三区| 亚洲国产成人一区| 另类图片国产| 欧美福利视频在线| 午夜亚洲影视| 可以免费看不卡的av网站| 久久精品中文| 日韩亚洲不卡在线| 欧美成人黄色小视频| 噜噜爱69成人精品| 国际精品欧美精品| 亚洲视频一区在线| 久久爱另类一区二区小说| 国产婷婷一区二区| 久久久久久久久久码影片| 亚洲精品一区二区三区婷婷月| 美女脱光内衣内裤视频久久影院| 久久精品首页| 中日韩高清电影网| 国产精品揄拍500视频| 欧美一区二区三区成人| 欧美大秀在线观看| 影音先锋日韩精品| 欧美日韩国产三区| 羞羞视频在线观看欧美| 夜夜嗨av一区二区三区中文字幕| 欧美丝袜一区二区| 久久激情五月婷婷| 国产精品久久国产精品99gif | 亚洲精品在线视频| 欧美va亚洲va日韩∨a综合色| 国产精品高清在线观看| 久久久夜夜夜| 亚洲综合99| 亚洲第一中文字幕在线观看| 亚洲欧美美女| 亚洲视频成人| 在线视频你懂得一区二区三区| 狠狠色丁香婷综合久久| 国产精品自拍三区| 国产精品日本欧美一区二区三区| 欧美精品在线一区| 欧美国产日韩a欧美在线观看| 欧美一区免费| 欧美国产精品日韩| 欧美色综合天天久久综合精品| 欧美无乱码久久久免费午夜一区 | 久久久精品国产免大香伊| 欧美在线视频观看免费网站| 久久亚洲精品一区| 欧美精品大片| 国产日韩欧美在线视频观看| 在线日韩中文| 午夜精品久久久久久久蜜桃app| 欧美在线观看一区| 99国产精品国产精品久久| 久久激情视频| 国产精品自在线| 亚洲视频在线观看视频| 麻豆免费精品视频| 亚洲一区二区三区精品在线| 欧美精品999| 亚洲男女自偷自拍图片另类| 久久久999| 亚洲电影免费在线观看| 国产精品成人一区二区网站软件 | 久久久久久久97| 国产精品第三页| 午夜精品视频在线观看| 亚洲高清视频中文字幕| 欧美一级网站| 伊人精品视频| 久久久久www| 久久青草福利网站| 一区二区三区日韩| 亚洲无毛电影| 国产亚洲精品久久久久动| 美女爽到呻吟久久久久| 久久免费黄色| 中文国产成人精品久久一| 亚洲在线国产日韩欧美| 欧美影院视频| 亚洲激情综合| 一区二区三区**美女毛片| 国产精品久线观看视频| 久久亚洲精品中文字幕冲田杏梨| 欧美亚洲视频| 亚洲图片欧美一区| 农村妇女精品| 久久久久久69| 国产欧美一区二区白浆黑人| 在线观看欧美精品| 在线天堂一区av电影| 亚洲黄色精品| 老牛国产精品一区的观看方式| 亚洲一区二区三区三| 久久手机免费观看| 亚洲欧美中文日韩在线| 亚洲国产精品v| 性亚洲最疯狂xxxx高清| 亚洲在线观看免费| 欧美精品在线一区| 欧美高清一区| 亚洲精品久久久久久一区二区| 久久精品日韩| 久久综合狠狠综合久久综合88| 欧美特黄一级大片| 艳女tv在线观看国产一区| 亚洲国产成人一区| 久久久天天操| 亚洲精品一线二线三线无人区| 亚洲精华国产欧美| 欧美精品一区二区三区很污很色的| 亚洲高清色综合|