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.特点
优点:将事件的发生和事件的处理分离开,并且可以动态的添加和删除处理方法
缺点:处理方法中如果有互相引用的情况,就会引起系统崩溃,而且解耦的手法影响了代码的执行效率(所有的设计模式几乎都有该缺点)
希望各位学习愉快;