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.特点

优点:将事件的发生和事件的处理分离开,并且可以动态的添加和删除处理方法

缺点:处理方法中如果有互相引用的情况,就会引起系统崩溃,而且解耦的手法影响了代码的执行效率(所有的设计模式几乎都有该缺点)

希望各位学习愉快;