欧美性猛交XXXX免费看蜜桃,成人网18免费韩国,亚洲国产成人精品区综合,欧美日韩一区二区三区高清不卡,亚洲综合一区二区精品久久

打開(kāi)APP
userphoto
未登錄

開(kāi)通VIP,暢享免費電子書(shū)等14項超值服

開(kāi)通VIP
C# 插件構架實(shí)戰(Jack H Hansen )

C# 插件構架實(shí)戰(Jack H Hansen )

一、引言

    1. 問(wèn)題的引入

    假設你設計的程序已經(jīng)部署到用戶(hù)的計算機上,并且能夠正常運行了。但是有一天,用戶(hù)打來(lái)了電話(huà)——他們要求增加新的功能。確定了用戶(hù)的需求后,你竟然發(fā)現原有的軟件架構已經(jīng)無(wú)法勝任新增任務(wù)的需求——你需要重新設計這個(gè)應用了!但問(wèn)題是,就算你又用了一個(gè)開(kāi)發(fā)周期完成了用戶(hù)需要的應用,卻不能保證用戶(hù)的需求不會(huì )再次變更。也就是說(shuō),需求蔓延的可能性依然存在。因此,這種情況下插件構架更能顯示出它的優(yōu)越性。

    2. 幾個(gè)解決方案的對比

    我總結了一下我所接觸到的插件構架,大致上可分為以下幾類(lèi):

i> 腳本式

    使用某種語(yǔ)言把插件的程序邏輯寫(xiě)成腳本代碼。而這種語(yǔ)言可以是 Python ,或是其他現存的已經(jīng)經(jīng)過(guò)用戶(hù)長(cháng)時(shí)間考驗的腳本語(yǔ)言。甚至,你可以自行設計一種腳本語(yǔ)言來(lái)配合你程序的特殊需要。當然,用當今最流行的 XML 是再合適不過(guò)了。

    這種形式的特點(diǎn)在于,稍有點(diǎn)編程知識的用戶(hù)就可以自行修改你的腳本( ^_^ 假如你不加密它的話(huà))。我們無(wú)法論證這是好處還是壞處。因為,這種情況所造成的后果是不可預知的。

ii> 動(dòng)態(tài)函數庫 DLL

    插件功能以動(dòng)態(tài)庫函數的形式存在。主程序通過(guò)某種渠道(插件編寫(xiě)者或某些工具)獲得插件 DLL 中的函數簽名,然后在合適的地方調用它們。用過(guò) Matlab 的讀者都知道, Matlab 中的各項功能幾乎都是些動(dòng)態(tài)鏈入的函數。

iii> 聚合式

    顧名思義,就是把插件功能直接寫(xiě)成 EXE 。主程序除了完成自己的職責外,還負責調度這些“插件”。我不喜歡這種形式。這使插件與插件之間,主程序與插件之間(主要是這一點(diǎn))的信息交流困難了許多。巴比倫塔的失敗 [1] 從某種程度上講就是信息交流無(wú)法實(shí)現造成的。

iv> COM 組件

    COM [2] 的產(chǎn)生給這個(gè)世界增添了幾分活力。只有接口!我們的插件需要做的只是實(shí)現程序定義的接口。主程序不需要知道插件怎樣實(shí)現預定的功能,它只需要通過(guò)接口訪(fǎng)問(wèn)插件,并提供主程序相關(guān)對象的接口。這樣一來(lái),主程序與各插件之間的信息交流就變得異常簡(jiǎn)單。并且,插件對于主程序來(lái)說(shuō)是完全透明的。

    3. 決策

    C# 是面向對象的程序設計語(yǔ)言。它提供了 interface 關(guān)鍵字來(lái)直接定義接口。同時(shí), System.Reflection 命名空間也提供了訪(fǎng)問(wèn)外部程序集的一系列相關(guān)對象。這就為我們在 C# 中實(shí)現插件構架打下了堅實(shí)的基礎。

    下面,我們將以一個(gè)具有插件構架的程序編輯器為例,來(lái)闡述這種構架在 C# 中的實(shí)現。

二、設計過(guò)程

    好了,現在我們準備把所有的核心代碼都放在 CSPluginKernel 命名空間中。用VSIDE建立一個(gè)C#類(lèi)庫工程。在命名空間 CSPluginKernel 中開(kāi)始我們的代碼。

    1. 接口設計

    我們的程序編輯器會(huì )向插件開(kāi)放正在編輯的文檔對象。程序啟動(dòng)后,就枚舉每一個(gè)插件并把它連接到主程序,同時(shí)傳遞主程序對象的接口。插件可以通過(guò)這個(gè)接口來(lái)請求主程序對象或訪(fǎng)問(wèn)主程序功能 。

    根據上面的需求,我們首先需要一個(gè)主程序接口:

public interface IApplicationObject {

     void Alert( string msg ); // 產(chǎn)生一條信息

     void ShowInStatusBar( string msg ); // 將指定的信息顯示在狀態(tài)欄

     IDocumentObject QueryCurrentDocument(); // 獲取當前使用的文檔對象

     IDocumentObject[] QueryDocuments(); // 獲取所有的文檔對象

     // 設置事件處理器

     void SetDelegate( Delegates whichOne , EventHandler targer );

}

// 目前只需要這一個(gè)事件

public enum Delegates {

     Delegate_ActiveDocumentChanged ,

}

    然后是 IDocumentObject 接口。插件通過(guò)這個(gè)接口訪(fǎng)問(wèn)編輯器對象。

///

/// 編輯器對象必須實(shí)現這個(gè)接口

///

public interface IDocumentObject {

     // 這些屬性是 RichTextBox 控件的相應的屬性映射

     string SelectionText { get ; set ; }

     Color SelectionColor { get ; set ; }

     Font SelectionFont { get ; set ; }

     int SelectionStart { get ; set ; }

     int SelectionLength { get ; set ; }

     string SelectionRTF { get ; set ; }

 

     bool HasChanges { get ; }

 

     void Select( int start , int length );

     void AppendText( string str );

 

     void SaveFile( string fileName );

     void SaveFile();

     void OpenFile( string fileName );

     void CloseFile();

}

    這個(gè)接口不需要過(guò)多解釋。這里我只實(shí)現了RichTextBox控件少數的幾個(gè)方法,其他可能用得到的,讀者自行添加即可。

   再然后,根據插件在其生命周期里的行為,設計插件的接口。

///

/// 本程序的插件必須實(shí)現這個(gè)接口

///

public interface IPlugin {

     ConnectionResult Connect( IApplicationObject app );

     void OnDestory();

     void OnLoad();

     void Run();

}

 

///

/// 表示插件與主程序連接的結果

///

public enum ConnectionResult {

    Connection_Success ,

    Connection_Failed

}

    主程序會(huì )首先調用 Connect() 方法,并傳遞 IApplicationObject 給插件。插件在這個(gè)過(guò)程中做一些初始化工作。然后,插件的 OnLoad() 方法被調用。在這之后,當主程序接收到調用插件的信號時(shí)(鍵盤(pán)、鼠標響應)就會(huì )調用插件的 Run() 方法來(lái)啟動(dòng)這個(gè)插件。程序結束時(shí),調用其 OnDestory() 方法。這樣,插件的生命才宣告結束。

    2. 插件信息的存儲與獲取

    一個(gè)插件需要有它的名稱(chēng) 、版本等信息。作為設計者的你,也一定要留下你的尊姓大名和個(gè)人網(wǎng)站等用來(lái)宣傳自己。 C# 的新特性——屬性, 就是一個(gè)很好的解決方案。因此我們定義一個(gè)從 System.Attribute 繼承來(lái)的類(lèi) PluginInfoArrtibute :

///

/// 用來(lái)指定一個(gè)插件的相關(guān)信息

///

public class PluginInfoAttribute : System.Attribute

{

     ///

     /// Deprecated. Do not use.

     ///

     public PluginInfoAttribute() {}

     public PluginInfoAttribute(

          string name , string version ,

          string author , string webpage , bool loadWhenStart ) {

          // 細節已略去

     }

     public string Name { get { return _Name; } }

     public string Version { get { return _Version; } }

     public string Author { get { return _Author; } }

     public string Webpage { get { return _Webpage; } }

     public bool LoadWhenStart { get { return _LoadWhenStart; } }

     ///

     /// 用來(lái)存儲一些有用的信息

     ///

     public object Tag {

          get { return _Tag; }

          set { _Tag = value ; }

     }

     ///

     /// 用來(lái)存儲序號

     ///

     public int Index {

          get { return _Index; }

          set { _Index = value ; }

     }

 

     private string _Name = "";

     private string _Version = "";

     private string _Author = "";

     private string _Webpage = "";

     private object _Tag = null ;

     private int _Index = 0;

     // 暫時(shí)不會(huì )用

     private bool _LoadWhenStart = true ;

}

     用這個(gè)類(lèi)修飾你的插件,并讓他實(shí)現 IPlugin 接口:

///

/// My Pluging 1( Just for test )

///

[

     PluginInfo(

          "My Pluging 1( Just for test )" ,

          "1.0" ,

          "Jack H Hansen" ,

          "http://blog.csdn.net/matrix2003b" , true )

]

public class MyPlugin1 : IPlugin {

     public MyPlugin1() { }

 

     #region IPlugin 成員

     // 細節已略去

     #endregion

 

     private IApplicationObject _App;

     private IDocumentObject _CurDoc;

}

    3. 加載插件

     現在就得用到 System.Refelction 命名空間了。程序在啟動(dòng)時(shí)會(huì )搜索 plugins 目錄下的每一個(gè)文件。對于每一個(gè)文件,如果它是一個(gè)插件,就用 Assembly 對象加載它。然后枚舉程序集中的每一個(gè)對象。判斷一個(gè)程序集是否為我們的插件的方法是判斷它是否直接或間接實(shí)現自 IPlugin。用下面的函數,傳遞從程序集枚舉的對象的System.Type。

private bool IsValidPlugin( Type t ) {

     bool ret = false ;

     Type[] interfaces = t.GetInterfaces();

     foreach ( Type theInterface in interfaces ) {

          if ( theInterface.FullName == "CSPluginKernel.IPlugin" ) {

               ret = true ;

               break ;

          }

     }

     return ret;

}

     若條件都滿(mǎn)足,IsValidPlugin() 就會(huì )返回 true 。接著(zhù)程序就會(huì )創(chuàng )建這個(gè)對象并把它存于一個(gè) ArrayList 中。

plugins.Add( pluginAssembly.CreateInstance( plugingType.FullName ) );

     現在,你就可以撰寫(xiě)測試代碼了。

三、源代碼

     由于篇幅所限,完整的源代碼(包含測試用例)請在下面的鏈接下載。下載后請用 VS.NET2003 打開(kāi),重新生成解決方案即可(需要 .NET Framework 1.1)。測試用例是一個(gè)在 RichTextBox 控件里插入紅色文本的插件。很簡(jiǎn)單,只作測試之用。

四、結語(yǔ)

     That's all! 有了這種插件構架,可憐的程序員們就再也不用為需求蔓延耗費心機了。另外,歡迎對本文以及本文的附加代碼作出評價(jià)。還有,就是,常去我的 Blog 看看~~ ^_^

本站僅提供存儲服務(wù),所有內容均由用戶(hù)發(fā)布,如發(fā)現有害或侵權內容,請點(diǎn)擊舉報。
打開(kāi)APP,閱讀全文并永久保存 查看更多類(lèi)似文章
猜你喜歡
類(lèi)似文章
也來(lái)學(xué)學(xué)插件式開(kāi)發(fā)
C# 插件式程序開(kāi)發(fā)
C#實(shí)現插件式開(kāi)發(fā)的一個(gè)Demo分享
SharpDevelop淺析_2_User Interface 創(chuàng )建易擴展且功能模塊松散耦合的應用程序 (轉 study log)
C#學(xué)習之接口 - Michael Xu - 博客園
C 接口工程實(shí)踐:有哪些實(shí)現方法?
更多類(lèi)似文章 >>
生活服務(wù)
分享 收藏 導長(cháng)圖 關(guān)注 下載文章
綁定賬號成功
后續可登錄賬號暢享VIP特權!
如果VIP功能使用有故障,
可點(diǎn)擊這里聯(lián)系客服!

聯(lián)系客服

欧美性猛交XXXX免费看蜜桃,成人网18免费韩国,亚洲国产成人精品区综合,欧美日韩一区二区三区高清不卡,亚洲综合一区二区精品久久