C#設計模式-觀察者模式

前言

最近開始花點心思研究下設計模式,主要仍是讓本身寫的代碼可重用性高、保證代碼可靠性。所謂設計模式,我找了下定義:是一套被反覆使用、多數人知曉的、通過分類編目的、代碼設計經驗的總結。毫無疑問,設計模式於己於他人於系統都是多贏的;設計模式使代碼編制真正工程化;設計模式是軟件工程的基石脈絡,如同大廈的結構同樣。編程

爲何要提倡「Design Pattern(設計模式)」?windows

根本緣由是爲了代碼複用,增長可維護性。所以此次咱們來學習下設計模式,最後會經過C#語言來實現這些設計模式做爲例子,深入理解其中的精髓。設計模式

定義

觀察者模式,有時被稱做發佈/訂閱模式,觀察者模式定義了一種一對多的依賴關係,讓多個觀察者對象同時監聽某一個主題對象。這個主題對象在狀態發生變化時,會通知全部觀察者對象,使它們可以自動更新本身。學習

特色

模式中具備的角色測試

        1。 抽象主題(Subject):它把全部觀察者對象的引用保存到一個彙集裏,每一個主題均可以有任何數量的觀察者。抽象主題提供一個接口,能夠增長和刪除觀察者對象。this

         2。 具體主題(ConcreteSubject):將有關狀態存入具體觀察者對象;在具體主題內部狀態改變時,給全部登記過的觀察者發出通知。spa

        3。抽象觀察者(Observer):爲全部的具體觀察者定義一個接口,在獲得主題通知時更新本身。設計

        4。具體觀察者(ConcreteObserver):實現抽象觀察者角色所要求的更新接口,以便使自己的狀態與主題狀態協調。code

·server

優缺點

優勢:

1、通知通訊

觀察者模式支持廣播通訊。被觀察者會向全部的註冊過的觀察者發出通知。

2、聚耦合

觀察者模式在被觀察者和觀察者之間創建了一個抽象的耦合,被觀察者並不知道任何一個具體的觀察者,只是保存着抽象觀察者的列表,每一個具體觀察者都符合一個抽象觀察者的接口。

缺點:

1、時間複雜度

若是一個被觀察者對象有不少的直接和間接的觀察者的話,將全部的觀察者都通知到會花費不少時間。

2、內聯不足

雖然觀察者模式能夠隨時使觀察者知道所觀察的對象發送了變化,可是觀察者模式沒有相應的機制使觀察者知道所觀察的對象是怎樣發生變化的。

3、容易出現循環調用

若是在被觀察者之間有循環依賴的話,被觀察者會觸發它們之間進行循環調用,致使系統崩潰,在使用觀察者模式應特別注意這點。

實現思路

下面以xmfdsh發佈一篇博客的例子來講明觀察者模式的實現。關注了xmfdsh的朋友們,即可以經過觀察者模式來實時獲得博客進行了更新的信息。當一個抽象模型有兩個方面,其中一個方面依賴於另外一個方面,將這二者封裝在獨立的對象中以使它們能夠各自獨立地改變和複用的狀況下。從方面的這個詞中能夠想到,觀察者模式確定在AOP(面向方面編程)中有所體現。所以這種需求使用觀察者模式來解決就再恰當不過了。

觀察者向目標「訂閱」它的改變,而目標發生改變後就「通知」全部已經「訂閱」了它的改變的觀察者,從而執行「訂閱」的內容。這種機制的好處在於下降耦合度,分工明確,目標只負責在自身狀態發生改變或作出某種行爲時向自身的訂閱清單發出「通知」,而不是直接調用觀察者的行爲(方法);觀察者只負責向目標「訂閱」它的變化,以及定義自身在收到目標「通知」後所須要作出的具體行爲(也就是訂閱的內容)

// 訂閱號抽象類
    public abstract class Blog
    {
        // 保存訂閱者列表
        private List<IObserver> observers = new List<IObserver>();

        public string Symbol { get; set; }//描寫訂閱號的相關信息
        public string Info { get; set; }//描寫這次update的信息
        public Blog(string symbol, string info)
        {
            this.Symbol = symbol;
            this.Info = info;
        }

        // 對同一個訂閱號,新增和刪除訂閱者的操做
        public void AddObserver(IObserver ob)
        {
            observers.Add(ob);
        }
        public void RemoveObserver(IObserver ob)
        {
            observers.Remove(ob);
        }

        public void Update()
        {
            // 遍歷訂閱者列表進行通知
            foreach (IObserver ob in observers)
            {
                if (ob != null)
                {
                    ob.Receive(this);
                }
            }
        }
    }

    // 具體訂閱號類
    public class MyBlog : Blog
    {
        public MyBlog(string symbol, string info)
            : base(symbol, info)
        {
        }
    }

    // 訂閱者接口
    public interface IObserver
    {
        void Receive(Blog tenxun);
    }

    // 具體的訂閱者類
    public class Subscriber : IObserver
    {
        public string Name { get; set; }
        public Subscriber(string name)
        {
            this.Name = name;
        }

        public void Receive(Blog xmfdsh)
        {
            Console.WriteLine("訂閱者 {0} 觀察到了{1}{2}", Name, xmfdsh.Symbol, xmfdsh.Info);
        }
    }

    // 客戶端測試
    class Program
    {
        static void Main(string[] args)
        {
            Blog xmfdsh = new MyBlog("xmfdsh", "發佈了一篇新博客");

            // 添加訂閱者
            xmfdsh.AddObserver(new Subscriber("王尼瑪"));
            xmfdsh.AddObserver(new Subscriber("唐馬儒"));
            xmfdsh.AddObserver(new Subscriber("王蜜桃"));
            xmfdsh.AddObserver(new Subscriber("敖尼瑪"));

            //更新信息
            xmfdsh.Update();
            //輸出結果,此時全部的訂閱者都已經獲得博客的新消息
            Console.ReadLine();
        }
    }

運行的效果圖以下

3

此類實現方法的類圖以下:

1

這個類圖是visual studio生成的,可能看起來比較混亂把,這樣的實現就是觀察者模式的實現。任什麼時候候,只要執行了Update方法,便會自動的去通知推送給訂閱了此訂閱號 的用戶,然而在C#中,咱們更多的是使用委託與事件來簡化觀察者模式的實現。

class Program
    {
        // 委託充當訂閱者接口類
        public delegate void NotifyEventHandler(object sender);

        // 抽象訂閱號類
        public class Blog
        {
            public NotifyEventHandler NotifyEvent;
            public string Symbol { get; set; }//描寫訂閱號的相關信息
            public string Info { get; set; }//描寫這次update的信息
            public Blog(string symbol, string info)
            {
                this.Symbol = symbol;
                this.Info = info;
            }

            #region 新增對訂閱號列表的維護操做
            public void AddObserver(NotifyEventHandler ob)
            {
                NotifyEvent += ob;
            }
            public void RemoveObserver(NotifyEventHandler ob)
            {
                NotifyEvent -= ob;
            }

            #endregion

            public void Update()
            {
                if (NotifyEvent != null)
                {
                    NotifyEvent(this);
                }
            }
        }

        // 具體訂閱號類
        public class MyBlog : Blog
        {
            public MyBlog(string symbol, string info)
                : base(symbol, info)
            {
            }
        }

        // 具體訂閱者類
        public class Subscriber
        {
            public string Name { get; set; }
            public Subscriber(string name)
            {
                this.Name = name;
            }

            public void Receive(Object obj)
            {
                Blog xmfdsh = obj as Blog;

                if (xmfdsh != null)
                {
                    Console.WriteLine("訂閱者 {0} 觀察到了{1}{2}", Name, xmfdsh.Symbol, xmfdsh.Info);
                }
            }
        }

        static void Main1(string[] args)
        {
            Blog xmfdsh = new MyBlog("xmfdsh", "發佈了一篇新博客");
            Subscriber wnm = new Subscriber("王尼瑪");
            Subscriber tmr = new Subscriber("唐馬儒");
            Subscriber wmt = new Subscriber("王蜜桃");
            Subscriber anm = new Subscriber("敖尼瑪");

            // 添加訂閱者
            xmfdsh.AddObserver(new NotifyEventHandler(wnm.Receive));
            xmfdsh.AddObserver(new NotifyEventHandler(tmr.Receive));
            xmfdsh.AddObserver(new NotifyEventHandler(wmt.Receive));
            xmfdsh.AddObserver(new NotifyEventHandler(anm.Receive));

            xmfdsh.Update();

            Console.WriteLine();
            Console.WriteLine();
            Console.WriteLine();
            Console.WriteLine();

            Console.WriteLine("移除訂閱者王尼瑪");
            xmfdsh.RemoveObserver(new NotifyEventHandler(wnm.Receive));
            xmfdsh.Update();

            Console.ReadLine();
        }
    }

運行的結果:

4

類圖:

2

 

總結

到這裏,觀察者模式就講完了,觀察者模式定義了一種一對多的依賴關係,讓多個觀察者對象能夠同時監聽某一個主題對象,這個主題對象在發生狀態變化時,會通知全部觀察者對象,使它們可以自動更新本身,所以在一些需求上是當一個對象的改變須要同時改變多個其餘對象的時候,且不知道多少個對象須要去通知改變的時候,觀察者模式就成了首選,這種模式的用的最多的,在個人開發經歷中即是windows phone手機客戶端的開發了,常常要用到這類的委託事件的處理,用多了後發現就習覺得常,這種模式也就沒那麼稀奇了。

源碼下載地址:http://files.cnblogs.com/xmfdsh/ConsoleApplication2.zip

相關文章
相關標籤/搜索