.NET責任鏈模式(混合單例模式,模板方法模式)-----製作與擴充能力驗證

來源:互聯網
上載者:User

標籤:style   class   blog   c   code   java   

.NET責任鏈模式、單例模式、模板方法模式混用  前言

  哇,看到題目挺長的,這個組合型的東西,到底能幹啥呢?本篇文章來一起琢磨琢磨,這兩天為了團隊的軟體趕工,我負責的那一塊叫:外掛程式管理器。我們團隊的成員用的語言還是挺分散的,本人C#,隊長VB.NET,還有其他成員寫易語言等,系統的功能外掛程式是我們分開寫的,各自用各自的喜歡的語言寫各個功能模組的外掛程式,最後用我開發的外掛程式管理器把所有的外掛程式整合到一起。這讓我很頭疼啊,一個C#版的外掛程式,一個VB.NET版的外掛程式,一個易語言的外掛程式,如果有新成員加入,又來個Python版的外掛程式,叫我如何是好。最普通、最爛的處理方法就是:寫很多版本的讀取器,然後使用if來根據外掛程式語言使用對應該版本的讀取器讀取資訊,哇,這如果來十幾種語言,豈不是坑爹。可能有人會說:引入Kernel32能解決非.NET語言的外掛程式讀取吧。確實目前使用了這種方案,能相容易語言,.NET語言就使用.NET的外掛程式Dll讀取方式,但是還不確定Kernel32能不能解決任何語言的外掛程式。所以為了讓自己有個後路,我結合題目所說的三種設計模式,寫了一個模板,下面看這個模板能幹嘛,為什麼要這樣用。如果有地方使用得不恰當的,希望各位朋友們強拍,我會努力學習改正,如果覺得可以的,點個推薦,謝謝~

 

架構展示與說明

                                       

  大家看下類圖,下面分別介紹各個類的職責。Plugin類是外掛程式的資料結構類,PluginType是一個枚舉,它的內容是定義了所有外掛程式的類型,例如DotNet,Python等,擴充的時候需要修改該枚舉。然後剩下的就是本章的重點了,使用者代碼Client使用IPluginAnalyzerable介面來讀取外掛程式資訊,該介面有兩個實作類別,一個是PluginAnalyzer(抽象類別,定義各個語言的讀取器的公用部分),該類實現模板方法模式和責任鏈模式,讓處理命令能在其子類之間互相推卸責任,其子類目前有兩個,分別是DotNet,Python的具體讀取器。最後一個類ComponentAnalyzer擔任封裝職責,將責任鏈初始化好,自己實現單例模式,提供給使用者代碼調用。所以,最後的效果是:擷取ComponentAnalyzer的執行個體,調用其中一個方法,該方法調用具體讀取器鏈,最後誰相應並且處理了這個方法調用使用者是不知道的,大概思路就是這樣。

 

實現過程

  本實現過程只是模板的實現,具體應用到項目中還需要做出相應的改變。

  事不宜遲,我們先實現Plugin類和PlugType枚舉:

    Plugin:

class Plugin    {        public Plugin(PluginType type,String pluginPath)        {            this.BelongType = type;            this.PluginPath = pluginPath;        }        public PluginType BelongType { set; get; }        public String PluginPath { set; get; }    }

    PlugType:

enum PluginType    {        DotNet=0,        Python=1,    }

  實現完兩個基本的類型以後,然後就來看下本篇的重頭戲,我會邊貼代碼邊附加上協助理解的說明。首先從最高層的IPluginAnalyzerable開始:

interface IPluginAnalyzerable    {         void Analyze(Plugin plugin);    }

 

  使用者代碼就是使用該介面的Analyze方法來處理傳入的外掛程式的,再下一層有兩個類,一個是抽象類別PluginAnalyzer,一個是ComponentAnalyzer。

abstract class PluginAnalyzer:IPluginAnalyzerable    {        protected PluginType analyzerType;        public void Analyze(Plugin plugin)        {            if (plugin.BelongType == this.analyzerType)            {                String author = GetAuthor(plugin);                String version = GetVersion(plugin);                Console.WriteLine(String.Format("\r\n分析者:{0},外掛程式類型:{1} \r\n{2}\r\n{3}",                     this.GetType().Name,plugin.BelongType,author, version));            }            else            {                if (nextAnalyzer != null)                {                    nextAnalyzer.Analyze(plugin);                }            }        }        private PluginAnalyzer nextAnalyzer;        public PluginAnalyzer NextAnalyzer        {            set            {                this.nextAnalyzer = value;            }            get             {                return this.nextAnalyzer;            }        }        protected abstract String GetAuthor(Plugin plugin);        protected abstract String GetVersion(Plugin plugin);    }

 

  解讀:

  每一個繼承本類的具體類都有兩個欄位

    1:所屬類型(PluginType枚舉),變數名為analyzerType。  

    2:下一個分析者(PluginAnalyzer),也就是兄弟類(同樣繼承PluginAnalyzer)。

  每一個繼承本類的具體類都需要重寫兩個方法GetAuthor和GetVersion,這兩個方法將會在模板方法Analyzer內部被使用。

  模板方法Analyzer首先判斷傳進來的外掛程式類型是否和自身可以處理的類型相同,如果相同則調用自身的方法處理,如果不同則把處理權推給自己的下一位分析者。這樣就完成了具體架構的搭建了。

  

  然後就是具體讀取器類了,各自有各自的處理相同任務的方式。都繼承PluginAnalyzer

    DotNetPluginAnalyzer(該類是處理.NET外掛程式的讀取器)

 

class DotNetPluginAnalyzer:PluginAnalyzer    {        public DotNetPluginAnalyzer()        {            base.analyzerType = PluginType.DotNet;        }        protected override string GetAuthor(Plugin plugin)        {            return "DotNet的外掛程式,作者名為:Jarvin";        }        protected override string GetVersion(Plugin plugin)        {            return "DotNet的外掛程式,版本號碼為:!!!V2014!!";        }    }

 

 

 

    PythonPluginAnalyzer(該類是處理Python外掛程式的讀取器)

 

class PythonPluginAnalyzer:PluginAnalyzer    {        public PythonPluginAnalyzer()        {            this.analyzerType = PluginType.Python;        }        protected override string GetAuthor(Plugin plugin)        {            return "Python的外掛程式,作者名為:Joker";        }        protected override string GetVersion(Plugin plugin)        {            return "Python的外掛程式,版本號碼為:V---很奇怪----";        }    }

 

 

 

  好了,如何使用?我將建立一個類,把這些讀取器封裝起來,並且形成一條鏈,提供一個統一的介面給使用者代碼調用,下面看我如何封裝的。

    ComponentAnalyzer

class ComponentAnalyzer:IPluginAnalyzerable    {        private ComponentAnalyzer()        {            rootAnalyzer = new DotNetPluginAnalyzer();            PythonPluginAnalyzer pythonAnalyzer = new PythonPluginAnalyzer();            rootAnalyzer.NextAnalyzer = pythonAnalyzer;        }        #region 單例模式實現        public static ComponentAnalyzer GetInstance()        {            return SingleHelper.GetInstance();        }        private class SingleHelper        {            private static ComponentAnalyzer me = new ComponentAnalyzer();            public static ComponentAnalyzer GetInstance()            {                return me;            }        }        #endregion                PluginAnalyzer rootAnalyzer;        public void Analyze(Plugin plugin)        {            rootAnalyzer.Analyze(plugin);        }    }

  很簡單的一個類,我們先看建構函式:把所有語言的讀取器串連起來,然後鏈頭是rootAnalyzer,我們每次調用Analyze方法都會調用rootAnalyzer對應的方法,讓其在內部傳遞。弄到這裡,差不多完成了,大家可以在最下面直接下載源碼運行看結果,下面給出用戶端測試類別。

class Programe    {        public static void Main(string[] args)        {            IPluginAnalyzerable dotnetAnalyzer=ComponentAnalyzer.GetInstance();            Console.WriteLine("輸入Q退出");            while(true)            {                Plugin plugin = RandomPlugin();                dotnetAnalyzer.Analyze(plugin);                if (Console.ReadLine().ToUpper() == "Q")                {                    break;                }            }        }        private static Plugin RandomPlugin()        {            Random random = new Random();            PluginType type = (PluginType)random.Next(0, 2);            String plaginPath = Path.GetRandomFileName();            Plugin result = new Plugin(type, plaginPath);            return result;        }    }
View Code

    測試結果:看,以一致的方式執行,但是會得到不一樣的效果,責任被推到合適的地方做出相應的處理。

  到這裡有人會說,那如何證明該模型的擴充性?? 好,下面我擴充一種語言讀取器,看我改了多少,對系統影響了多少?

 

擴充性測試

   我以Ruby為例。

    1.在PluginType中添加一個枚舉內容Ruby:。

    2.添加一個Ruby讀取器:

    3.在ComponentAnalyzer(前面說的封裝器)中,把該讀取器添加到鏈條上!

    

    為了測試,在用戶端代碼中修改Random隨機產生數,使其能產生3,大功告成!(這是測試相關,我們沒有修改實際用戶端任何代碼)

     順利擴充!!!我們修改的只是上層的代碼,對於底層,也提供了擴充點,符合對修改封閉,對擴充開放。

 

總結

  完成了,大家也累了,希望有不對的地方大家大力拍,面向組合編程,面向介面編程,不要面向具體實作類別編程,這是我學習設計模式感受最深的一句話。謝謝大家觀看。下面提供完整源碼。

                                   完整Demo下載

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.