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


1.定義

觀察者模式說白了就是事件;之前沒有觀察者模式的時候,當我們需要考察屬性的狀態然后作出相應的處理,我們只能當狀態滿足的時候去調用方法。

不過這樣就造成了事件處理和事件綁定在了一起,一旦我們要添加其他的處理功能,就不得不修改原有的檢測代碼,對於修改並不友好。

 

2.觀察者模式的發展

2.1 一個簡單的需求

對於一個簡單的流程比如說,檢測誰有沒有燒開,以前沒有事件的時候,如果我們就需要寫如下代碼;

public class BoilWater
{
    public int waterTemperature = 0;

    public void Boil()
    {
        for (int i = 0; i < 100; i++)
        {
            waterTemperature = i;
            Thread.Sleep(100);
            if (waterTemperature == 100)
            {
                Call();
            }
        }
    }

    public void Call()
    {
        Console.Write("The Water is Boiled!");
    }
}

如上就是檢測看,誰有沒有燒開,如果水燒開了(到達100C),就調用通知方法(Call);

但是上面的代碼缺點也很明顯,那就是:一旦我們要增加水燒開后的處理程序,我們就不得不修改Boil方法;

那有沒有辦法可以讓我們不修改代碼的情況下,在運行中動態的去修改水燒開時的處理程序呢?答案是肯定的,那就是使用觀察者模式;

2.2 觀察者模式

public class BoilWater
{
    public int waterTemperature = 0;

    public IList<RunInter> Observers = new List<RunInter>();

    public void Boil()
    {
        for (int i = 0; i < 100; i++)
        {
            waterTemperature = i;
            Thread.Sleep(100);
            if (waterTemperature == 100)
            {
                CallAllObserve();
            }
        }
    }

    public void CallAllObserve()
    {
        foreach (var item in Observers)
        {
            item.Run();
        }
    }

    public void AddObserver(RunInter runner)
    {
        Observers.Add(runner);
    }

    public void RemoveObserver(RunInter runner)
    {
        Observers.Remove(runner);
    }
}

    public interface RunInter
    {
        void Run();
    }

    public class Call : RunInter
    {
        public void Run()
        {
            Console.Write("The Water is Boiled!");
        }
    }

    public class DoOtherThing : RunInter
    {
        public void Run()
        {
            Console.Write("Do Other Things");
        }
    }

這里我們在被觀察的類中放一個存儲接口的列表,然后在事件滿足的時候,將列表中的每一個接口都執行一遍,而且因為有AddObserver和RemoveObserver方法,因此在程序運行的過程中我們也可以動態的添加新的處理代碼,或刪除已有的處理代碼。

但是這樣做確實是有一點繁瑣,要定義接口,還要再檢測類中加上對應的列表,還好.NET已經為我們設計了完美的替代方案,那就是使用委托和事件;

2.3 使用委托和事件來實現觀察者模式

public class BoilWater
{
    public int waterTemperature = 0;

    private event Action actions;

    public void Boil()
    {
        for (int i = 0; i < 100; i++)
        {
            waterTemperature = i;
            Thread.Sleep(100);
            if (waterTemperature == 100)
            {
                actions();
            }
        }
    }

    public void AddObserver(Action runner)
    {
        actions += runner;
    }

    public void RemoveObserver(Action runner)
    {
        actions -= runner;
    }
}

調用的時候只需要:

var boilWater = new BoilWater();
boilWater.AddObserver(() =>
{
    Console.WriteLine("Water is Boiled");
});
boilWater.AddObserver(() =>
{
    Console.WriteLine("Do Other Things");
});

這樣當水開的時候,兩個控制台打印的方法,都會被執行了。

其實在這里的Action就是.Net自帶的委托對象,其實委托我們在和上面的代碼對比后,就可以認為他是一系列相似方法的集合列表,當執行委托之后,這個集合中的每一個方法就會依次被執行(有先后順序,並不是並發執行);

但這種方式就為我們實現觀察者模式的邏輯提供的很大的方便。

2.4 委托和事件的區別

2.3中的代碼我使用了event關鍵字,就是講委托聲明為事件了,很多人區分不出委托和事件的區別,其實很簡單,事件是一種特殊的委托;

既然是委托,其實說到底他還是方法的集合,當執行事件后,這個集合中的所有方法都會被執行;

區別在於,委托可以在委托所屬的類外面進行添加和刪除操作;但是事件不行,事件只能在事件所屬的類內部進行添加和刪除操作。

 

3.特點

優點:將事件的發生和事件的處理分離開,並且可以動態的添加和刪除處理方法

缺點:處理方法中如果有互相引用的情況,就會引起系統崩潰,而且解耦的手法影響了代碼的執行效率(所有的設計模式幾乎都有該缺點)

希望各位學習愉快;


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM