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

清源游民 gameogre@gmail.com

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

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

常見的錯(cuò)誤
一些程序員,當(dāng)進(jìn)行插件系統(tǒng)的設(shè)計(jì)時(shí),可能會(huì)給每一個(gè)作為插件使用的動(dòng)態(tài)庫添加一個(gè)如下函數(shù)類似的函數(shù):PluginClass *createInstance(const char*);
然后它們讓插件去提供一些類的實(shí)現(xiàn)。引擎用期望的對(duì)象名對(duì)加載的插件逐個(gè)進(jìn)行查詢,直到某個(gè)插件返回,這是典型的設(shè)計(jì)模式中“職責(zé)鏈”模式的做法。一些更聰明的程序員會(huì)做出新的設(shè)計(jì),使插件在引擎中注冊(cè)自己,或是用定制的實(shí)現(xiàn)替代引擎內(nèi)部缺省實(shí)現(xiàn):
Void dllStartPlugin(PluginManager &pm);
Void dllStopPlugin(PluginManager &pm);
第一種設(shè)計(jì)的主要問題是:插件工廠創(chuàng)建的對(duì)象需要使用reinterpret_cast<>來進(jìn)行轉(zhuǎn)換。通常,插件從共同基類(這里指PluginClass)派生,會(huì)引用一些不安全的感覺。實(shí)際上,這樣做也是沒意義的,插件應(yīng)該“默默”地響應(yīng)輸入設(shè)備的請(qǐng)求,然后提交結(jié)果給輸出設(shè)備。
在這種結(jié)構(gòu)下,為了提供相同接口的多個(gè)不同實(shí)現(xiàn),需要的工作變得異常復(fù)雜,如果插件可以用不同名字注冊(cè)自己(如Direct3DRenderer and OpenGLRenderer),但是引擎不知道哪個(gè)具體實(shí)現(xiàn)對(duì)用戶的選擇是有效的。假如把所有可能的實(shí)現(xiàn)列表硬編碼到程序中,那么使用插件結(jié)構(gòu)的目的也沒有意義了。
假如插件系統(tǒng)通過一個(gè)框架或是庫(如游戲引擎) 實(shí)現(xiàn),架構(gòu)師也肯定會(huì)把功能暴露給應(yīng)用程序使用。這樣,會(huì)帶來一些問題像如何在應(yīng)用程序中使用插件,插件作者如何引擎的頭文件等,這包含了潛在的三者之間版本沖突的可能性。
單獨(dú)的工廠
接口,是被引擎清楚定義的,而不是插件。引擎通過定義接口來指導(dǎo)插件做什么工作,插件具體實(shí)現(xiàn)功能。我們讓插件注冊(cè)自己的引擎接口的特殊實(shí)現(xiàn)。當(dāng)然直接創(chuàng)建插件實(shí)現(xiàn)類的實(shí)例并注冊(cè)是比較笨的做法。這樣使得同一時(shí)刻所有可能的實(shí)現(xiàn)同時(shí)存在,占用內(nèi)存與CPU資源。解決的辦法是工廠類,它唯一的目的是在請(qǐng)求時(shí)創(chuàng)建另外類的實(shí)例。如果引擎定義了接口與插件通信,那么也應(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)該考慮插件如何在引擎中注冊(cè)它們的工廠,引擎又如何實(shí)際地使用這些注冊(cè)的插件。一種選擇是與存在的代碼很好的接合,這通過寫插件管理器來完成。這使得我們可以控制哪些組件允許被擴(kuò)展。
class PluginManager {
  void registerRenderer(std::auto_ptr<RendererFactory> RF);
  void registerSceneManager(std::auto_ptr<SceneManagerFactory> SMF);
};
當(dāng)引擎需要一個(gè)渲染器時(shí),它會(huì)訪問插件管理器,看哪些渲染器已經(jīng)通過插件注冊(cè)了。然后要求插件管理器創(chuàng)建期望的渲染器,插件管理器于是使用工廠類來生成渲染器,插件管理器甚至不需要知道實(shí)現(xiàn)細(xì)節(jié)。
插件由動(dòng)態(tài)庫組成,后者導(dǎo)出一個(gè)可以被插件管理器調(diào)用的函數(shù),用以注冊(cè)自己:
void registerPlugin(PluginManager &PM);
插件管理器簡(jiǎn)單地在特定目錄下加載所有dll文件,檢查它們是否有一個(gè)名為registerPlugin()的導(dǎo)出函數(shù)。當(dāng)然也可用xml文檔來指定哪些插件要被加載。 

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

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

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

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

posted on 2007-04-17 15:54 清源游民 閱讀(5309) 評(píng)論(8)  編輯 收藏 引用 所屬分類: C++

FeedBack:
# re: 用C++實(shí)現(xiàn)的一種插件體系結(jié)構(gòu)-----概述
2007-04-17 23:44 | 黃大仙
# re: 用C++實(shí)現(xiàn)的一種插件體系結(jié)構(gòu)-----概述
2007-04-18 15:57 | Kooyu
很多時(shí)候經(jīng)常變動(dòng)的是接口而不是實(shí)現(xiàn)。  回復(fù)  更多評(píng)論
  
# re: 用C++實(shí)現(xiàn)的一種插件體系結(jié)構(gòu)-----概述
2007-04-18 21:22 | missdeer
@Kooyu
接口經(jīng)常變動(dòng)就是設(shè)計(jì)得太糟糕了,要么就學(xué)COM,已有接口永遠(yuǎn)不變,要么就添加新接口  回復(fù)  更多評(píng)論
  
# re: 用C++實(shí)現(xiàn)的一種插件體系結(jié)構(gòu)-----概述
2007-04-18 21:48 | 清源游民
@missdeer
我也認(rèn)為,如果接口經(jīng)常變動(dòng)的話,那么設(shè)計(jì)接口也沒什么意義了,設(shè)計(jì)接口就是希望能應(yīng)對(duì)可能的變化。但真的是不存在一勞永逸的事情,這是個(gè)矛盾。  回復(fù)  更多評(píng)論
  
# re: 用C++實(shí)現(xiàn)的一種插件體系結(jié)構(gòu)-----概述
2007-05-08 08:10 | Ulti
“如果把GPL組件封裝在插件中,你就不必發(fā)布插件的源碼”
這句應(yīng)該譯成:
“如果把GPL組件封裝在插件中,你就只需要發(fā)布插件的源碼”  回復(fù)  更多評(píng)論
  
# re: 用C++實(shí)現(xiàn)的一種插件體系結(jié)構(gòu)-----概述
2007-05-08 09:34 | 清源游民
致Ulti:
謝謝,是我粗心了。  回復(fù)  更多評(píng)論
  
# re: 用C++實(shí)現(xiàn)的一種插件體系結(jié)構(gòu)-----概述
2008-08-07 15:18 | zhangws
如果把GPL組件封裝在插件中,你就不必發(fā)布插件的源碼。

樓主翻譯反了,
如果把GPL組件封裝在插件中,你就只需要發(fā)布插件的源碼。  回復(fù)  更多評(píng)論
  
# re: 用C++實(shí)現(xiàn)的一種插件體系結(jié)構(gòu)-----概述
2008-08-07 15:20 | zhangws
樓主刪了吧,我沒有注意到有人提醒了,不好意思  回復(fù)  更多評(píng)論
  
<2007年4月>
25262728293031
1234567
891011121314
15161718192021
22232425262728
293012345

留言簿(35)

隨筆分類(78)

隨筆檔案(74)

文章檔案(5)

搜索

  •  

最新評(píng)論

閱讀排行榜

評(píng)論排行榜

青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品
  • <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>
            老司机成人网| 日韩一级精品视频在线观看| 欧美在线网站| 乱人伦精品视频在线观看| 欧美一区二区三区免费看| 一区二区视频免费完整版观看| 欧美激情一区三区| 午夜精品一区二区三区在线| 欧美二区在线看| 欧美在线亚洲一区| 一区二区三区四区五区在线| 国产在线视频欧美一区二区三区| 欧美精品久久99| 亚洲精品久久久久| 新狼窝色av性久久久久久| 亚洲三级视频| 尤物yw午夜国产精品视频| 国产精品v欧美精品v日韩| 欧美一区二区三区视频免费| 欧美华人在线视频| 香蕉久久久久久久av网站 | 鲁大师成人一区二区三区| 亚洲视频视频在线| 欧美激情久久久| 欧美在线免费看| 欧美专区中文字幕| 亚洲欧美中日韩| 欧美一区二区三区日韩| 一本综合精品| 亚洲深夜福利| 中文精品99久久国产香蕉| 亚洲精品1区| 日韩亚洲欧美在线观看| 亚洲日本在线观看| 亚洲日本在线视频观看| 亚洲成色999久久网站| 国产婷婷精品| 激情成人av在线| 亚洲经典三级| 日韩午夜电影av| 日韩午夜电影在线观看| 亚洲国产成人tv| 一本一本a久久| 国产精品99久久久久久久久久久久 | 欧美激情第10页| 91久久亚洲| 一区二区三区视频在线| 亚洲清纯自拍| 欧美成人一区二区三区| 浪潮色综合久久天堂| 亚洲国产精品免费| 亚洲视频观看| 欧美一区在线视频| 美女精品自拍一二三四| 欧美日韩色婷婷| 国产一区二区三区在线观看免费视频| 国产香蕉97碰碰久久人人| 1024成人网色www| 一区二区三区不卡视频在线观看| 亚洲欧美日韩精品久久亚洲区| 欧美国产日韩一二三区| 久久久久久久精| 国产精品午夜在线观看| 在线欧美不卡| 欧美一级专区| 99精品99久久久久久宅男| 午夜免费在线观看精品视频| 欧美精品免费播放| 国产真实乱偷精品视频免| 亚洲一二三级电影| 欧美二区不卡| 久久精品二区| 国产一区二区三区精品久久久| 亚洲精品乱码久久久久久按摩观| 性高湖久久久久久久久| 欧美成人一区二区三区| 午夜视频一区| 国产精品亚洲综合天堂夜夜| 亚洲天堂av电影| 亚洲黄页一区| 欧美另类综合| 一本大道久久精品懂色aⅴ| 亚洲大胆人体在线| 久久久久久久久久码影片| 亚洲国产综合视频在线观看| 欧美成年人视频| 亚洲国产精品欧美一二99| 猛干欧美女孩| 欧美r片在线| 夜夜躁日日躁狠狠久久88av| 一区二区三区日韩精品视频| 国产精品一卡| 欧美电影免费观看高清| 欧美在线综合| 亚洲精品国产精品乱码不99按摩| 欧美日韩理论| 久久中文久久字幕| 欧美国产另类| 欧美综合第一页| 免费在线看一区| 欧美一区二区三区在| 欧美主播一区二区三区美女 久久精品人| 在线色欧美三级视频| 99精品视频免费| 国产专区综合网| 最新国产成人在线观看| 国产精品自在欧美一区| 欧美激情一区二区| 欧美日韩麻豆| 欧美大香线蕉线伊人久久国产精品| 欧美日韩精品综合在线| 久久久噜噜噜久久中文字幕色伊伊| 美脚丝袜一区二区三区在线观看 | 国产精品99久久不卡二区| 亚洲一区二区av电影| 亚洲伦理一区| 久久综合亚州| 欧美制服第一页| 国产精品jizz在线观看美国 | 久久九九精品99国产精品| 伊人久久亚洲美女图片| 一区二区日本视频| 亚洲精品乱码久久久久久蜜桃麻豆 | 国内精品久久久久影院色| 一区二区精品| 亚洲乱码视频| 久久综合九色九九| 久久免费的精品国产v∧| 国产精品日韩| 日韩一级网站| 亚洲美女少妇无套啪啪呻吟| 媚黑女一区二区| 欧美第一黄网免费网站| 亚洲第一伊人| 麻豆精品在线播放| 久热re这里精品视频在线6| 国产精品久久久久久久久久三级 | 亚洲免费在线观看视频| 亚洲精选视频在线| 蜜桃av综合| 欧美激情一区二区三区蜜桃视频 | 国产日韩精品一区二区三区在线| 亚洲永久视频| 亚洲欧美一区二区三区久久 | 亚洲视频视频在线| 亚洲承认在线| 欧美日韩在线精品一区二区三区| 91久久精品网| 亚洲自拍偷拍网址| 国产日韩一级二级三级| 久久久成人精品| 亚洲国产精品ⅴa在线观看 | 欧美第十八页| 99成人免费视频| 国产麻豆午夜三级精品| 欧美资源在线观看| 欧美黄网免费在线观看| 亚洲欧美成人一区二区三区| 国产精品一香蕉国产线看观看 | 在线看片成人| 老司机免费视频一区二区| 99re国产精品| 久久国产视频网站| 亚洲国产精品99久久久久久久久| 欧美日韩免费看| 久久黄色网页| 夜夜嗨一区二区三区| 巨胸喷奶水www久久久免费动漫| 亚洲精品在线看| 国产精品一区二区久久国产| 欧美在线播放一区| 99re热这里只有精品免费视频| 久久一区中文字幕| 亚洲欧美激情视频在线观看一区二区三区 | 国内成+人亚洲+欧美+综合在线| 亚洲精品乱码视频| 黄色一区二区在线| 欧美日韩国产123| 欧美一二三区精品| 一区二区三区视频在线播放| 欧美大片在线看免费观看| 久久久久欧美精品| 亚洲永久在线| 亚洲一区二区三区四区五区午夜 | 亚洲韩国精品一区| 激情婷婷欧美| 很黄很黄激情成人| 国产在线拍揄自揄视频不卡99| 欧美日韩午夜视频在线观看| 久久亚洲影院| 久久久一二三| 你懂的一区二区| 久久综合色8888| 另类亚洲自拍| 麻豆精品91| 欧美不卡视频一区发布| 久久精品国产免费| 久久久久久久久久久久久9999| 久久精品人人做人人爽| 久久久福利视频|