Observer设计模式是针对:一个对象对多个对象中,一个对象发生状态改变,其他附属对象发生相应的更新。是一种松耦合的设计模式。
例子:
假设我们有个高档的热水器,我们给它通上电,当水温超过95度的时候:1、扬声器会开始发出语音,告诉你水的温度;2、液晶屏也会改变水温的显示,来提示水已经快烧开了。
现在我们需要写个程序来模拟这个烧水的过程,我们将定义一个类来代表热水器,我们管它叫:Heater,它有代表水温的字段,叫做temperature;当然,还有必不可少的给水加热方法BoilWater(),一个发出语音警报的方法MakeAlert(),一个显示水温的方法,ShowMsg()。
namespace Delegate { class Heater { private int temperature; // 水温 // 烧水 public void BoilWater() { for (int i = 0; i <= 100; i++) { temperature = i; if (temperature > 95) { MakeAlert(temperature); ShowMsg(temperature); } } } // 发出语音警报 private void MakeAlert(int param) { Console.WriteLine("Alarm:嘀嘀嘀,水已经 {0} 度了:" , param); } // 显示水温 private void ShowMsg(int param) { Console.WriteLine("Display:水快开了,当前温度:{0}度。" , param); } } class Program { static void Main() { Heater ht = new Heater(); ht.BoilWater(); } } }
上面的例子显然能完成我们之前描述的工作,但是却并不够好。现在假设热水器由三部分组成:热水器、警报器、显示器,它们来自于不同厂商并进行了组装。那么,应该是热水器仅仅负责烧水,它不能发出警报也不能显示水温;在水烧开时由警报器发出警报、显示器显示提示和水温。
这时候,上面的例子就应该变成这个样子:
1 // 热水器 2 public class Heater { 3 private int temperature; 4 5 // 烧水 6 private void BoilWater() { 7 for (int i = 0; i <= 100; i++) { 8 temperature = i; 9 } 10 } 11 } 12 13 // 警报器 14 public class Alarm{ 15 private void MakeAlert(int param) { 16 Console.WriteLine("Alarm:嘀嘀嘀,水已经 {0} 度了:" , param); 17 } 18 } 19 20 // 显示器 21 public class Display{ 22 private void ShowMsg(int param) { 23 Console.WriteLine("Display:水已烧开,当前温度:{0}度。" , param); 24 } 25 }
这里就出现了一个问题:如何在水烧开的时候通知报警器和显示器?在继续进行之前,我们先了解一下Observer设计模式,Observer设计模式中主要包括如下两类对象:
- Subject:监视对象,它往往包含着其他对象所感兴趣的内容。在本范例中,热水器就是一个监视对象,它包含的其他对象所感兴趣的内容,就是temprature字段,当这个字段的值快到100时,会不断把数据发给监视它的对象。
- Observer:监视者,它监视Subject,当Subject中的某件事发生的时候,会告知Observer,而Observer则会采取相应的行动。在本范例中,Observer有警报器和显示器,它们采取的行动分别是发出警报和显示水温。
在本例中,事情发生的顺序应该是这样的:
- 警报器和显示器告诉热水器,它对它的温度比较感兴趣(注册)。
- 热水器知道后保留对警报器和显示器的引用。
- 热水器进行烧水这一动作,当水温超过95度时,通过对警报器和显示器的引用,自动调用警报器的MakeAlert()方法、显示器的ShowMsg()方法。
1 using System; 2 using System.Collections.Generic; 3 using System.Linq; 4 using System.Text; 5 using System.Threading; 6 7 namespace Delegate_Event 8 { 9 class Program 10 { 11 static void Main(string[] args) 12 { 13 Alarm a = new Alarm(); 14 Display d=new Display(); 15 16 Heater h = new Heater(); 17 18 h.makeBoilDelegateEvent += a.MakeAlert; 19 h.makeBoilDelegateEvent += d.showMsg; 20 h.OnmakeBoilDelegate("123"); 21 Console.ReadKey(); 22 } 23 } 24 25 26 //热水器 27 public class Heater 28 { 29 public delegate void BoilDelegate(int name); 30 public event BoilDelegate makeBoilDelegateEvent; 31 32 public void OnmakeBoilDelegate(string name) 33 { 34 for (int i = 0; i < 1000; i++) 35 { 36 Thread.Sleep(2000); 37 38 if (makeBoilDelegateEvent != null) 39 { 40 makeBoilDelegateEvent(i); 41 } 42 } 43 44 } 45 } 46 47 //报警器 48 public class Alarm 49 { 50 //报警器有个报警的动作 51 public void MakeAlert(int c) 52 { 53 if (c >= 100) 54 { 55 Console.WriteLine("Alarm:咕咕咕......咕咕咕......咕咕咕......,水烧开了!"); 56 } 57 } 58 } 59 60 //显示器 61 public class Display 62 { 63 //显示温度 64 public void showMsg(int c) 65 { 66 Console.WriteLine("Display:现在温度"+c+"摄氏度!"); 67 } 68 } 69 }
1 using System; 2 using System.Collections.Generic; 3 using System.Text; 4 5 namespace Delegate { 6 // 热水器 7 public class Heater { 8 private int temperature; 9 public string type = "RealFire 001"; // 添加型号作为演示 10 public string area = "China Xian"; // 添加产地作为演示 11 //声明委托 12 public delegate void BoiledEventHandler(Object sender, BoiledEventArgs e); 13 public event BoiledEventHandler Boiled; //声明事件 14 15 // 定义BoiledEventArgs类,传递给Observer所感兴趣的信息 16 public class BoiledEventArgs : EventArgs { 17 public readonly int temperature; 18 public BoiledEventArgs(int temperature) { 19 this.temperature = temperature; 20 } 21 } 22 23 // 可以供继承自 Heater 的类重写,以便继承类拒绝其他对象对它的监视 24 protected virtual void OnBoiled(BoiledEventArgs e) { 25 if (Boiled != null) { // 如果有对象注册 26 Boiled(this, e); // 调用所有注册对象的方法 27 } 28 } 29 30 // 烧水。 31 public void BoilWater() { 32 for (int i = 0; i <= 100; i++) { 33 temperature = i; 34 if (temperature > 95) { 35 //建立BoiledEventArgs 对象。 36 BoiledEventArgs e = new BoiledEventArgs(temperature); 37 OnBoiled(e); // 调用 OnBolied方法 38 } 39 } 40 } 41 } 42 43 // 警报器 44 public class Alarm { 45 public void MakeAlert(Object sender, Heater.BoiledEventArgs e) { 46 Heater heater = (Heater)sender; //这里是不是很熟悉呢? 47 //访问 sender 中的公共字段 48 Console.WriteLine("Alarm:{0} - {1}: ", heater.area, heater.type); 49 Console.WriteLine("Alarm: 嘀嘀嘀,水已经 {0} 度了:", e.temperature); 50 Console.WriteLine(); 51 } 52 } 53 54 // 显示器 55 public class Display { 56 public static void ShowMsg(Object sender, Heater.BoiledEventArgs e) { //静态方法 57 Heater heater = (Heater)sender; 58 Console.WriteLine("Display:{0} - {1}: ", heater.area, heater.type); 59 Console.WriteLine("Display:水快烧开了,当前温度:{0}度。", e.temperature); 60 Console.WriteLine(); 61 } 62 } 63 64 class Program { 65 static void Main() { 66 Heater heater = new Heater(); 67 Alarm alarm = new Alarm(); 68 69 heater.Boiled += alarm.MakeAlert; //注册方法 70 heater.Boiled += (new Alarm()).MakeAlert; //给匿名对象注册方法 71 heater.Boiled += new Heater.BoiledEventHandler(alarm.MakeAlert); //也可以这么注册 72 heater.Boiled += Display.ShowMsg; //注册静态方法 73 74 heater.BoilWater(); //烧水,会自动调用注册过对象的方法 75 } 76 } 77 } 78 79 输出为: 80 Alarm:China Xian - RealFire 001: 81 Alarm: 嘀嘀嘀,水已经 96 度了: 82 Alarm:China Xian - RealFire 001: 83 Alarm: 嘀嘀嘀,水已经 96 度了: 84 Alarm:China Xian - RealFire 001: 85 Alarm: 嘀嘀嘀,水已经 96 度了: 86 Display:China Xian - RealFire 001: 87 Display:水快烧开了,当前温度:96度。 88 // 省略 ...
原文地址:http://www.cnblogs.com/jimmyzhang/archive/2007/09/23/903360.html