C#設計模式---觀察者模式簡單例子

來源:互聯網
上載者:User

標籤:設計模式   c#   

在開發過程中經常遇到一個模組中的 一個方法調用了其他模組中相關的方法

比如說在一個系統中,如果出現了錯誤,就調用專門進行錯誤處理的模組中的方法進行錯誤處理

而因為錯誤處理的操作有很多,所以將這些具體的操作封裝在其他的模組中

在專門進行錯誤處理的模組中調用其他模組中的錯誤操作方法

這樣一來在主系統中只要執行個體化專門進行錯誤處理的模組對象

並調用其相關的方法,其他模組中的具體方法也都會被執行

這時專門進行錯誤處理的模組被稱為發行者

其他擁有具體錯誤操作的模組稱為訂閱者

只要發行者一發布資訊(方法被調用)

所有的訂閱者都會相應(具體方法也會執行)


最直接的做法是在模組中引用並執行個體化其他模組的對象

然後調用其方法

下面給出一個簡單的例子,用類來類比模組

首先是具體的錯誤操作

在例子中有三個具體的錯誤操作

分別為:發送郵件,發出警報,視窗抖動

/// <summary>    /// 具體的錯誤處理方式類(模組)1,此為訂閱者    /// </summary>    public class Handle1    {        /// <summary>        /// 出現錯誤時做出發送郵件的處理        /// </summary>        public void ErrorHanding()        {            Console.WriteLine("出現錯誤!發送了一封郵件到管理員!");        }    }
/// <summary>    /// 具體的錯誤處理方式類(模組)2,此為訂閱者    /// </summary>    public class Handle2    {        /// <summary>        /// 出現錯誤時做出發出警報的處理        /// </summary>        public void ErrorHanding()        {            Console.WriteLine("出現錯誤!警報!!!!!!!!!!!!!!!!");        }    }

/// <summary>    /// 具體的錯誤處理方式類(模組)3,此為訂閱者    /// </summary>    public class Handle3    {        /// <summary>        /// 出現錯誤時做出視窗抖動的處理        /// </summary>        public void ErrorHanding()        {            Console.WriteLine("出現錯誤!我抖!!!!!!!!!!!!!!!!!!!!!!!!");        }    }

專門進行錯誤處理的模組

/// <summary>    /// 系統錯誤處理相關的類(模組),此為資訊的發行者    /// </summary>    public class ErrorAbout    {        /// <summary>        /// 錯誤處理的方法,主模組中通過調用此方法來觸發一系列的錯誤處理        /// </summary>        public void ErrorHanding()        {            //執行個體化每一個訂閱者,並調用其方法            Handle1 handle1 = new Handle1();            handle1.ErrorHanding();            Handle2 handle2 = new Handle2();            handle2.ErrorHanding();            Handle3 handle3 = new Handle3();            handle3.ErrorHanding();        }    }
主系統中:

class Program    {        static void Main(string[] args)        {            //假設在這個位置,系統出現了錯誤,需要進行錯誤處理            Console.WriteLine("系統出現了嚴重錯誤,需要進行一些處理~~~");            //執行個體化錯誤處理相關的類(發行者)            ErrorAbout errorAbout = new ErrorAbout();            //只要發行者的方法一執行,所有訂閱者的方法也都會被執行            errorAbout.ErrorHanding();            Console.ReadKey();        }    }
運行結果如下:


這麼做完全可以實現需要的功能

但是有何不妥呢?

在主模組中發現錯誤的時候new一個錯誤模組的執行個體,然後調用處理錯誤的方法
在錯誤模組中直接new各個子模組的執行個體,然後在處理錯誤的方法中依次執行
這樣一來,錯誤模組和子模組之間就直接耦合在一起

這是面向過程的處理方式

在子模組方法發生改變的時候,或者錯誤模組需要添加新的處理錯誤的方法時
要對已經開發完畢的錯誤模組進行修改,違反了開放封閉原則
所以要對錯誤模組和子模組進行解耦(物件導向思想)


這時候就用到了觀察者(Observer)模式,又稱為發布-訂閱模式等

實現的方法有兩種

方法一:使用委託
方法二:使用介面
兩種方法都實現了對錯誤模組和子模組的隔離
對兩個模組的操作都是在主模組中完成的



Demo1:使用委託實現

具體錯誤處理方法的委託

/// <summary>    /// 具體錯誤處理方法的委託    /// </summary>    public delegate void ErrorHandle();

/// <summary>    /// 系統錯誤處理相關的類(模組),此為資訊的發行者    /// </summary>    public class ErrorAbout    {        //定義一個 具體錯誤處理方法委託 的變數        private ErrorHandle errorHandle;        //向外界提供一個可以向內部委託變數添加的方法        public void AddErrorHanding(ErrorHandle errorHandle)        {            //將傳進來的方法加入委託變數中            if (this.errorHandle == null)            {                this.errorHandle = new ErrorHandle(errorHandle);            }            else            {                this.errorHandle += new ErrorHandle(errorHandle);            }        }        /// <summary>        /// 錯誤處理的方法,主模組中通過調用此方法來觸發一系列的錯誤處理        /// </summary>        public void ErrorHanding()        {            //調用委託,相當於調用了委託中的所有方法            errorHandle();        }    }
在使用委託時要注意

不能直接讓外界操作內部的委託

一定要封裝一個方法提供外界以一個安全的方式來操作內部的委託(為什麼說這是一個安全的方式呢?因為在這個方法裡面只能給委託添加方法,不能進行其他的任何操作)

如果直接將委託變數暴露給外界

那麼外界就可以調用委託變數的所有方法

有可能會造成將原本的方法刪除或者覆蓋等情況

(這就是為什麼會有事件這個東西存在的原因)

這也是一種物件導向的思想


在主模組中

class Program    {        static void Main(string[] args)        {            //假設在這個位置,系統出現了錯誤,需要進行錯誤處理            Console.WriteLine("系統出現了嚴重錯誤,需要進行一些處理~~~");            //執行個體化錯誤處理相關的類(發行者)            ErrorAbout errorAbout = new ErrorAbout();            //向發行者添加訂閱者            Handle1 handle1 = new Handle1();            errorAbout.AddErrorHanding(handle1.ErrorHanding);            Handle2 handle2 = new Handle2();            errorAbout.AddErrorHanding(handle1.ErrorHanding);            Handle3 handle3 = new Handle3();            errorAbout.AddErrorHanding(handle1.ErrorHanding);            //只要發行者的方法一執行,所有訂閱者的方法也都會被執行            errorAbout.ErrorHanding();            Console.ReadKey();        }    }
這樣一來就實現了對錯誤模組和其他模組的解耦

任何錯誤具體的操作模組發生了變化

只要在其使用者--主模組中修改即可


Demo2:使用介面實現

首先需要提供一個統一的介面給具體的錯誤處理方式類(模組)

在發行者中可以通過這個介面調用實現了這個介面的所有訂閱者


具體的錯誤處理方式類(模組)需要實現的介面

 /// <summary>    /// 具體的錯誤處理方式類(模組)需要實現的介面,在發行者中通過此介面可以統一調用訂閱者的方法    /// </summary>    public interface IHandle    {        void ErrorHanding();    }


具體的錯誤處理方式類(模組)

 /// <summary>    /// 具體的錯誤處理方式類(模組)1,此為訂閱者    /// </summary>    public class Handle1:IHandle    {        /// <summary>        /// 出現錯誤時做出發送郵件的處理        /// </summary>        public void ErrorHanding()        {            Console.WriteLine("出現錯誤!發送了一封郵件到管理員!");        }    }

/// <summary>    /// 具體的錯誤處理方式類(模組)2,此為訂閱者    /// </summary>    public class Handle2:IHandle    {        /// <summary>        /// 出現錯誤時做出發出警報的處理        /// </summary>        public void ErrorHanding()        {            Console.WriteLine("出現錯誤!警報!!!!!!!!!!!!!!!!");        }    }

/// <summary>        /// 出現錯誤時做出視窗抖動的處理        /// </summary>        public void ErrorHanding()        {            Console.WriteLine("出現錯誤!我抖!!!!!!!!!!!!!!!!!!!!!!!!");        }


發行者

/// <summary>    /// 系統錯誤處理相關的類(模組),此為資訊的發行者    /// </summary>    public class ErrorAbout    {        /// <summary>        /// 訂閱者介面的集合        /// </summary>        private List<IHandle> handles = new List<IHandle>();        /// <summary>        /// 在主模組中可以通過此方法向 訂閱者介面的集合 中添加新的訂閱者(具體處理錯誤的方法)        /// </summary>        /// <param name="handle"></param>        public void AddErrorHanding(IHandle handle)        {            handles.Add(handle);        }        /// <summary>        /// 錯誤處理的方法,主模組中通過調用此方法來觸發一系列的錯誤處理        /// </summary>        public void ErrorHanding()        {            //遍曆訂閱者介面的集合            foreach (var handle in handles)            {                //執行集合中的每個錯誤處理的方法                handle.ErrorHanding();            }        }    }

主模組中

class Program    {        static void Main(string[] args)        {            //假設在這個位置,系統出現了錯誤,需要進行錯誤處理            Console.WriteLine("系統出現了嚴重錯誤,需要進行一些處理~~~");            //執行個體化錯誤處理相關的類(發行者)            ErrorAbout errorAbout = new ErrorAbout();            //向發行者添加訂閱者            errorAbout.AddErrorHanding(new Handle1());            errorAbout.AddErrorHanding(new Handle2());            errorAbout.AddErrorHanding(new Handle3());            //只要發行者的方法一執行,所有訂閱者的方法也都會被執行            errorAbout.ErrorHanding();            Console.ReadKey();        }    }


委託實現C#觀察者模式簡單例子下載:

點擊開啟連結

介面實現C#觀察者模式簡單例子下載:

點擊開啟連結






相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在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.