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

用C++實現插件體系結構

Posted on 2009-06-30 13:41 RichardHe 閱讀(1512) 評論(0)  編輯 收藏 引用 所屬分類: [再轉]
http://www.yuanma.org/data/2007/0807/article_2796.htm
本文討論一種簡單卻有效的插件體系結構,它使用C++,動態鏈接庫,基于面向對象編程的思想
<BR>首先來看一下使用插件機制能給我們帶來哪些方面的好處,從而在適當時候合理的選擇使用
。<BR>1,&nbsp;<SPAN style="COLOR: #0000ff">增強代碼的透明度與一致性</SPAN>
:因為插件通常會封裝第三方類庫或是其他人編寫的代碼,需要清晰地定義出接口,用清晰一致的接口來面對所有事情。
你的代碼也不會被轉換程序或是庫的特殊定制需求弄得亂七糟。
改善工程的模塊化</SPAN>:你的代碼被清析地分成多個獨立的模塊,可以把它們安置在子工程中的文件組中。
這種解耦處理使得創建出的組件更加容易重用
更短的編譯時間</SPAN>:如果僅僅是為了解釋某些類的聲明,而這些類內部使用了外部庫,
編譯器不再需要解析外部庫的頭文件了,因為具體實現是以私有的形式完成。
更換與增加組件</SPAN>:假如你需要向用戶發布補丁,那么更新單獨的插件而不是替代每一個安裝了的文件更為有效。
當使用新的渲染器或是新的單元類型來擴展你的游戲時,能過向引擎提供一組插件,可以很容易的實現。
在關閉源代碼的工程中使用GPL代碼</SPAN>:一般,假如你使用了GPL發布的代碼,那么你也需要開放你的源代碼。
然而,如果把GPL組件封裝在插件中,你就不必發布插件的源碼。
介紹<BR></SPAN>先簡單解釋一下什么是插件系統以及它如何工作:在普通的程序中,假如你需要代碼執行一項特殊的任務,
你有兩種選擇:要么你自己編寫,要么你尋找一個已經存在的滿足你需要的庫。現在,你的要求變了,那你只好重寫代碼或是尋找另一個不同的庫。
無論是哪種方式,都會導致你框架代碼中的那些依賴外部庫的代碼重寫。<BR>現在,我們可以有另外一種選擇:在插件系統中,
工程中的任何組件不再束縛于一種特定的實現(像渲染器既可以基于OpenGL,也可以選擇Direct3D),它們會從框架代碼中剝離出來,
通過特定的方法被放入動態鏈接庫之中。<BR>所謂的特定方法包括在框架代碼中創建接口,這些接口使得框架與動態庫解耦。
插件提供接口的實現。我們把插件與普通的動態鏈接庫區分開來是因為它們的加載方式不同:程序不會直接鏈接插件,
而可能是在某些目錄下查找,如果發現便進行加載。所有插件都可以使用一種共同的方法與應用進行聯結。
常見的錯誤<BR></SPAN>一些程序員,當進行插件系統的設計時,可能會給每一個作為插件使用的動態庫添加一個如下函數類似的函數:
PluginClass *createInstance(const char*);
然后它們讓插件去提供一些類的實現。引擎用期望的對象名對加載的插件逐個進行查詢,
直到某個插件返回,這是典型的設計模式中“職責鏈”模式的做法。一些更聰明的程序員會做出新的設計,使插件在引擎中注冊自己,
或是用定制的實現替代引擎內部缺省實現:
Void dllStartPlugin(PluginManager &amp;pm);
Void dllStopPlugin(PluginManager &amp;pm);
第一種設計的主要問題是:插件工廠創建的對象需要使用reinterpret_cast
;來進行轉換。通常,插件從共同基類(這里指PluginClass)派生,會引用一些不安全的感覺。實際上,這樣做也是沒意義的,
插件應該“默默”地響應輸入設備的請求,然后提交結果給輸出設備。<BR>在這種結構下,為了提供相同接口的多個不同實現,需要的工作變得異常復雜,
如果插件可以用不同名字注冊自己(如Direct3DRenderer and OpenGLRenderer),但是引擎不知道哪個具體實現對用戶的選擇是有效的。
假如把所有可能的實現列表硬編碼到程序中,那么使用插件結構的目的也沒有意義了。<BR>假如插件系統通過一個框架或是庫(如游戲引擎) 實現,
架構師也肯定會把功能暴露給應用程序使用。這樣,會帶來一些問題像如何在應用程序中使用插件,插件作者如何引擎的頭文件等,
這包含了潛在的三者之間版本沖突的可能性。<BR><SPAN style="COLOR: #0000ff">單獨的工廠</SPAN><BR>接口,是被引擎清楚定義的,而不是插件。
引擎通過定義接口來指導插件做什么工作,插件具體實現功能。我們讓插件注冊自己的引擎接口的特殊實現。當然直接創建插件實現類的實例并注冊是比較笨的做法。
這樣使得同一時刻所有可能的實現同時存在,占用內存與CPU資源。解決的辦法是工廠類,它唯一的目的是在請求時創建另外類的實例。
如果引擎定義了接口與插件通信,那么也應該為工廠類定義接口:
typename Interface Factory { virtual Interface *create() = 0; };
class Renderer { virtual void beginScene() = 0; virtual void endScene() = 0;};
typedef Factory;Renderer; RendererFactory;
選擇1: 插件管理器
接下來應該考慮插件如何在引擎中注冊它們的工廠,引擎又如何實際地使用這些注冊的插件。一種選擇是與存在的代碼很好的接合,
這通過寫插件管理器來完成。這使得我們可以控制哪些組件允許被擴展。
class PluginManager
{void registerRenderer(std::auto_ptr ;RendererFactory ; RF);
void registerSceneManager(std::auto_ptr ;SceneManagerFactory ; SMF); };
當引擎需要一個渲染器時,它會訪問插件管理器,看哪些渲染器已經通過插件注冊了。
然后要求插件管理器創建期望的渲染器,插件管理器于是使用工廠類來生成渲染器,插件管理器甚至不需要知道實現細節。
插件由動態庫組成,后者導出一個可以被插件管理器調用的函數,用以注冊自己:
void registerPlugin(PluginManager ;PM);
>插件管理器簡單地在特定目錄下加載所有dll文件,檢查它們是否有一個名為registerPlugin()的導出函數。
當然也可用xml文檔來指定哪些插件要被加載。 
選擇 2: 完整地集成Fully Integrated 除了使用插件管理器,
也可以從頭設計代碼框架以支持插件。最好的方法是把引擎分成幾個子系統
,構建一個系統核心來管理這些子系統。可能像下面這樣:
class Kernel {StorageServer &amp;getStorageServer() const; GraphicsServer &amp;getGraphicsServer() const;};
class StorageServer {<BR><SPAN style="COLOR: #008000">; //提供給插件使用,注冊新的讀檔器
void addArchiveReader(std::auto_ptr&lt;ArchiveReader&gt; AL);// 查詢所有注冊的讀檔器,直到找到可以打開指定格式的讀檔器
std::auto_ptr&lt;Archive&gt; openArchive(const std::string &amp;sFilename);
<BR>};<BR>&nbsp;<BR>class GraphicsServer {<BR>&nbsp;<SPAN style="COLOR: #008000"> // 供插件使用,用來添加驅動<BR></SPAN>&nbsp;
void addGraphicsDriver(std::auto_ptr&lt;GraphicsDriver&gt; AF);<BR>&nbsp; <BR>&nbsp; <SPAN style="COLOR: #008000">// 獲取有效圖形驅動的數目
<BR></SPAN>&nbsp; size_t getDriverCount() const;<BR><SPAN style="COLOR: #008000">&nbsp;//返回驅動<BR></SPAN>&nbsp;
GraphicsDriver &amp;getDriver(size_t Index);<BR>};<BR>這里有兩個子系統,它們使用” Server”作為后綴。
第一個Server內部維護一個有效圖像加載器的列表,每次當用戶希望加載一幅圖片時,圖像加載器被一一查詢,
直到發現一個特定的實現可以處理特定格式的圖片。另一個子系統有一個GraphicsDrivers的列表,它們作為Renderers的工廠來使用。
可以是Direct3DgraphicsDriver或是OpenGLGraphicsDrivers,它們分別負責Direct3Drenderer與OpenGLRenderer的創建。引擎提供有效的驅動列表供用戶選擇使用,
通過安裝一個新的插件,新的驅動也可以被加入。<BR><BR><SPAN style="COLOR: #0000ff">版本</SPAN><BR>在上面兩個可選擇的方法中,
不強制要求你把特定的實現放到插件中。假如你的引擎提供一個讀檔器的默認實現,以支持自定義文件包格式。你可以把它放到引擎本身,
當StorageServer 啟動時自動進行注冊。<BR>現在還有一個問題沒有討論:假如你不小心的話,與引擎不匹配(例如,已經過時的)插件會被加載
子系統類的一些變化或是插件管理器的改變足以導致內存布局的改變,當不匹配的插件試圖注冊時可能發生沖突甚至崩潰。比較討厭的是,這些在調試時難與發現。
 幸運的是,辨認過時或不正確的插件非常容易。最可靠的是方法是在你的核心系統中放置一個預處理常量。任何插件都有一個函數,
它可以返回這個常量給引擎:<BR><SPAN style="COLOR: #008000">// Somewhere in your core system<BR>
</SPAN>#define MyEngineVersion 1;<BR>&nbsp;<BR><SPAN style="COLOR: #008000">// The plugin</SPAN><BR>extern int getExpectedEngineVersion()
 {<BR>&nbsp; return MyEngineVersion;<BR>}<BR>在這個常量被編譯到插件后,當引擎中的常量改變時,任何沒有進行重新編譯的插件它的 
getExpectedEngineVersion ()方法會返回以前的那個值。引擎可以根據這個值,拒絕加載不匹配的插件。為了使插件可以重新工作,必須重新編譯它。
當然,最大的危險是你忘記了更新常量值。無論如何,你應該有個自動版本管理工具幫助你。 </P>

posts - 94, comments - 138, trackbacks - 0, articles - 94

Copyright © RichardHe

青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品
  • <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>
            亚洲精品在线观看免费| 欧美午夜精品久久久久久超碰| 一区二区三区产品免费精品久久75| 亚洲一区久久| 亚洲午夜av| 欧美黄色免费网站| 欧美1区视频| 韩日在线一区| 欧美在线free| 久久aⅴ国产欧美74aaa| 欧美系列精品| 亚洲乱亚洲高清| 日韩一区二区电影网| 久久夜色精品一区| 久热精品视频| 在线观看成人一级片| 久久国产精品第一页| 久久免费视频网| 国内不卡一区二区三区| 性做久久久久久久免费看| 午夜激情久久久| 国产精品嫩草影院一区二区| av成人免费观看| 亚洲视频www| 国产精品v欧美精品v日韩 | 一区二区国产在线观看| 欧美激情一区二区三区在线视频观看| 欧美成人免费大片| 亚洲风情亚aⅴ在线发布| 米奇777在线欧美播放| 欧美国产精品劲爆| 亚洲级视频在线观看免费1级| 美女国内精品自产拍在线播放| 欧美激情精品| 一区二区三区 在线观看视| 欧美日韩网站| 亚洲一区国产视频| 久久久久久电影| 极品中文字幕一区| 免费看的黄色欧美网站| 亚洲人屁股眼子交8| 亚洲欧美国产高清| 国产一区二区三区在线观看视频| 久久久精品tv| 亚洲精选视频免费看| 亚洲综合首页| 国产亚洲永久域名| 欧美成人免费在线视频| 99在线观看免费视频精品观看| 先锋亚洲精品| 亚洲福利视频专区| 欧美日韩视频一区二区| 午夜性色一区二区三区免费视频 | 午夜精品久久久| 国产一区再线| 欧美日韩国产精品成人| 亚洲在线播放电影| 你懂的国产精品永久在线| 99一区二区| 国产日本欧美视频| 欧美激情1区| 亚洲欧美日本伦理| 欧美成人有码| 欧美一区国产一区| 亚洲免费观看| 一区二区三区在线高清| 欧美日韩美女在线观看| 久久男人资源视频| 亚洲午夜精品一区二区三区他趣| 嫩草成人www欧美| 亚洲欧美中文另类| 亚洲人成人一区二区三区| 国产精品日韩久久久久| 免费观看久久久4p| 亚洲欧美日韩天堂| 日韩视频一区二区在线观看 | 国产一区清纯| 欧美日韩一区二区在线 | 久久在线免费观看视频| 亚洲性感激情| 亚洲激情网站免费观看| 久久久精品久久久久| 亚洲一区二区免费看| 亚洲国产欧美精品| 国产亚洲成精品久久| 欧美午夜美女看片| 欧美激情国产精品| 久久综合色婷婷| 欧美在线免费一级片| 亚洲特级片在线| 日韩天堂在线视频| 91久久精品国产91久久| 欧美bbbxxxxx| 麻豆精品一区二区av白丝在线| 久久国产精品久久w女人spa| 亚洲一级片在线观看| 日韩视频免费看| 亚洲人成精品久久久久| 亚洲国产精品va| 亚洲电影免费观看高清| 黄色成人在线网址| 国产一二精品视频| 国产亚洲一区二区三区在线播放| 国产精品美女久久久久久久| 国产精品v欧美精品v日韩精品 | 国产欧美 在线欧美| 国产精品激情偷乱一区二区∴| 欧美日韩高清不卡| 欧美激情a∨在线视频播放| 久久综合五月| 欧美刺激午夜性久久久久久久| 欧美国产日韩一二三区| 欧美激情一二区| 欧美美女福利视频| 欧美午夜精品伦理| 国产精品一二一区| 国模 一区 二区 三区| 国内一区二区三区| 亚洲第一页中文字幕| 亚洲激情网址| 一本大道久久a久久综合婷婷| 亚洲午夜视频| 久久久高清一区二区三区| 美女日韩欧美| 91久久精品www人人做人人爽 | 亚洲成人在线视频播放 | 欧美国产精品日韩| 亚洲区在线播放| 一区二区三区蜜桃网| 欧美一区二区免费观在线| 久久蜜桃资源一区二区老牛 | 欧美日韩国产精品 | 亚洲精品黄色| 亚洲综合精品| 久久久亚洲精品一区二区三区| 欧美大片国产精品| 99re6这里只有精品视频在线观看| 亚洲永久免费观看| 久久婷婷蜜乳一本欲蜜臀| 欧美久久久久| 国产视频一区在线观看一区免费| 激情国产一区| 亚洲视频第一页| 久久女同互慰一区二区三区| 亚洲人体一区| 久久精品伊人| 欧美性事免费在线观看| 狠狠久久亚洲欧美| 在线一区二区三区四区五区| 久久久久综合网| 亚洲精品乱码久久久久久| 欧美亚洲尤物久久| 欧美精品情趣视频| 精品91视频| 午夜在线一区| 亚洲国产专区| 欧美一区=区| 欧美视频在线观看| 亚洲电影下载| 欧美在线观看日本一区| 91久久精品日日躁夜夜躁国产| 欧美一区二区三区在线观看视频| 欧美日韩免费在线观看| 亚洲国产岛国毛片在线| 久久精品国产亚洲一区二区三区| 亚洲精品视频啊美女在线直播| 久久久久久九九九九| 国产精品伊人日日| 中文亚洲免费| 亚洲欧洲日产国码二区| 久久久一本精品99久久精品66| 国产精品美女一区二区在线观看| 亚洲免费观看高清在线观看| 欧美成人综合| 久久久久久久网站| 国产亚洲欧美日韩日本| 亚洲欧美国产高清| 在线亚洲高清视频| 欧美日韩免费一区二区三区| 亚洲精品少妇| 亚洲高清免费| 毛片基地黄久久久久久天堂| 在线 亚洲欧美在线综合一区| 久久精品欧美| 欧美一区二区三区在线观看| 国产精品一区二区三区观看| 亚洲欧美精品在线| 一区二区三区不卡视频在线观看| 欧美精选午夜久久久乱码6080| 亚洲精品自在在线观看| 亚洲国产毛片完整版| 免费看黄裸体一级大秀欧美| 91久久在线| 亚洲国产精品久久久久秋霞影院 | 久久精品国产一区二区三区免费看| 亚洲午夜久久久久久久久电影院 | 亚洲国产高清视频| 麻豆视频一区二区| 免费人成精品欧美精品| 亚洲人永久免费|