设计模式之观察者模式

注解:观察者模式构造出对象之间一对多的代懒关系。

要点:抽取容易发生变化的部分把这些可能会随着日后需求改变的"一组行为"抽取出来,变成"一族算法"。

总结:1.多用包含,少用继承(解除继承所代来的单一性) 。

          2.抽取可能会发生变化的部分,既使在项目初期所能预料到的变化很少。

          3.面向父类或接口编程。

 

  项目结构如下图:

 

为了清晰思路,特做了个小图

 

 

就好像报社(主题)天天再印报纸,所有的用户(观察者)每天都能收到报社送来的最新的报纸。如果用户(观察者)不想订阅报纸了,那么只要告诉报社不要给我报纸就可以了。

程序的设计理念为 主题控制观察者的接口,通知观察者是否有新的数据需要更新。观察者控制主题的接口随时告诉主题,是否增加了新的观察者。以便主题在一下次数据更新时能知道又来了新的观察者,并为其发送数据。

 

代码说话:

主题接口
 1 using System.Collections.Generic;
 2 using 观察者模式.Observer;
 3 
 4 namespace 观察者模式.Subject
 5 {
 6     /// <summary>
 7     /// 主题
 8     /// </summary>
 9     public interface ISubject
10     {
11         /// <summary>
12         /// 多个观察者
13         /// </summary>
14         List<IObserver> Observers { getset; }
15 
16         /// <summary>
17         /// 向主题注册观察者
18         /// </summary>
19         /// <param name="observer"></param>
20         void RegisterObserver(IObserver observer);
21 
22         /// <summary>
23         /// 向主题删除观察者
24         /// </summary>
25         /// <param name="observer"></param>
26         void RemoveObserver(IObserver observer);
27 
28         /// <summary>
29         /// 通知观察者
30         /// </summary>
31         void NotifyObserver();
32     }
33 }
34 


 观察者接口

 1 using 观察者模式.Subject;
 2 
 3 namespace 观察者模式.Observer
 4 {
 5     /// <summary>
 6     /// 观察者
 7     /// </summary>
 8     public interface IObserver
 9     {
10         /// <summary>
11         /// 主题
12         /// </summary>
13         ISubject Subject { getset; }
14 
15         /// <summary>
16         /// 更新观察者数据
17         /// </summary>
18         /// <param name="pressure">气压</param>
19         /// <param name="temp">温度</param>
20         /// <param name="direction">风向</param>
21         void UpdateData(float pressure, float temp, string direction);
22     }
23 }
24 


显示数据接口

 1 namespace 观察者模式.Observer
 2 {
 3     /// <summary>
 4     /// 显示数据
 5     /// </summary>
 6     public interface IDisplayElement
 7     {
 8         void DisplayData(string displayData);
 9     }
10 }
11 


具体的主题

 1 using System.Collections.Generic; 
 2 using 观察者模式.Observer;
 3 
 4 namespace 观察者模式.Subject
 5 {
 6     /// <summary>
 7     /// 此类为具体的主题
 8     /// 假设此类是从气向局提取数据
 9     /// </summary>
10     public class WeaterData : ISubject
11     {
12         public WeaterData()
13         {
14             Observers = new List<IObserver>();
15         }
16 
17         public List<IObserver> Observers { getset; }
18 
19         #region 属性
20         /// <summary>
21         /// 气压
22         /// </summary>
23         public float Pressure { getset; }
24 
25         /// <summary>
26         /// 温度
27         /// </summary>
28         public float Temp { getset; }
29 
30         /// <summary>
31         /// 风向
32         /// </summary>
33         public string Direction { getset; }
34         #endregion
35 
36         /// <summary>
37         /// 向主题注册观察者
38         /// </summary>
39         /// <param name="observer"></param>
40         public void RegisterObserver(IObserver observer)
41         {
42             Observers.Add(observer);
43         }
44 
45         /// <summary>
46         /// 向主题删除观察者
47         /// </summary>
48         /// <param name="observer"></param>
49         public void RemoveObserver(IObserver observer)
50         {
51             var index = Observers.IndexOf(observer);
52             Observers.RemoveAt(index);
53         }
54 
55         /// <summary>
56         /// 通知观察者
57         /// </summary>
58         public void NotifyObserver()
59         {
60             for (int i = 0, j = Observers.Count; i < j; i++)
61             {
62                 Observers[i].UpdateData(Pressure, Temp, Direction);
63             }
64         }
65 
66         /// <summary>
67         /// 当天气改变的时候
68         /// 会去通知每一个观察者
69         /// </summary>
70         /// <param name="pressure"></param>
71         /// <param name="temp"></param>
72         /// <param name="direction"></param>
73         public void WeaterChanged(float pressure, float temp, string direction)
74         {
75             this.Pressure = pressure;
76             this.Temp = temp;
77             this.Direction = direction;
78             NotifyObserver();
79         }
80     }
81 }
82 


 观察者一

 1 using 观察者模式.Subject;
 2 
 3 namespace 观察者模式.Observer
 4 {
 5     /// <summary>
 6     /// 中国天气
 7     /// 中国观察者
 8     /// </summary>
 9     public class ChinaWeater : IObserver, IDisplayElement
10     {
11         public ChinaWeater(ISubject subject)
12         {
13             this.Subject = subject;
14             this.Subject.RegisterObserver(this);//告诉主题我来了
15         }
16 
17         /// <summary>
18         /// 这个属性似乎没什么意义
19         /// 但是我们在删除观察者时可能会用到它的引用哦。
20         /// </summary>
21         public ISubject Subject { getset; }
22 
23         /// <summary>
24         /// 更新数据
25         /// </summary>
26         /// <param name="pressure"></param>
27         /// <param name="temp"></param>
28         /// <param name="direction"></param>
29         public void UpdateData(float pressure, float temp, string direction)
30         {
31             var displayData = string.Format("中国天气\r\n气压:{0}\r\n温度:{1}\r\n风向:{2}", pressure, temp, direction);
32             DisplayData(displayData);
33         }
34 
35         /// <summary>
36         /// 显示数据
37         /// </summary>
38         /// <returns></returns>
39         public void DisplayData(string displayData)
40         {
41             System.Windows.Forms.MessageBox.Show(displayData);
42         }
43     }
44 }
45 


 观察者2

 1 using 观察者模式.Subject;
 2 
 3 namespace 观察者模式.Observer
 4 {
 5     /// <summary>
 6     /// 美国天气
 7     /// </summary>
 8     public class USAWeater : IObserver, IDisplayElement
 9     {
10         public USAWeater(ISubject subject)
11         {
12             this.Subject = subject;
13             this.Subject.RegisterObserver(this);    //告诉主题我来了
14         }
15 
16         /// <summary>
17         /// 这个属性似乎没什么意义
18         /// 但是我们在删除观察者时可能会用到它的引用哦。
19         /// </summary>
20         public ISubject Subject { getset; }
21 
22         /// <summary>
23         /// 更新数据
24         /// </summary>
25         /// <param name="pressure"></param>
26         /// <param name="temp"></param>
27         /// <param name="direction"></param>
28         public void UpdateData(float pressure, float temp, string direction)
29         {
30             var displayData = string.Format("美国天气\r\n气压:{0}\r\n温度:{1}\r\n风向:{2}\r\n温度和气压总计:{3}", pressure, temp, direction, (pressure + temp));
31             DisplayData(displayData);
32         }
33 
34         /// <summary>
35         /// 显示数据
36         /// </summary>
37         /// <returns></returns>
38         public void DisplayData(string displayData)
39         {
40             System.Windows.Forms.MessageBox.Show(displayData);
41         }
42     }
43 }
44 


观察者3

 1 using System; 
 2 using 观察者模式.Subject;
 3 
 4 namespace 观察者模式.Observer
 5 {
 6     /// <summary>
 7     /// 德国天气
 8     /// 德国观察者
 9     /// </summary>
10     public class GermanyWeater : IObserver, IDisplayElement
11     {
12         public GermanyWeater(ISubject subject)
13         {
14             this.Subject = subject;
15             this.Subject.RegisterObserver(this);    //告诉主题我来了
16         }
17 
18         /// <summary>
19         /// 这个属性似乎没什么意义
20         /// 但是我们在删除观察者时可能会用到它的引用哦。
21         /// </summary>
22         public ISubject Subject { getset; }
23 
24         /// <summary>
25         /// 更新数据
26         /// </summary>
27         /// <param name="pressure"></param>
28         /// <param name="temp"></param>
29         /// <param name="direction"></param>
30         public void UpdateData(float pressure, float temp, string direction)
31         {
32             var displayData = string.Format("德国天气\r\n气压:{0}\r\n温度:{1}\r\n风向:{2}\r\n气温最大值{3}", pressure, temp, direction, Math.Abs(pressure));
33             DisplayData(displayData);
34         }
35 
36         /// <summary>
37         /// 显示数据
38         /// </summary>
39         /// <returns></returns>
40         public void DisplayData(string displayData)
41         {
42             System.Windows.Forms.MessageBox.Show(displayData);
43         }
44     }
45 }
46 


一个测试的小应用程序

 

 

 

 

 

 UML图如下:

 

 

posted @ 2009-12-02 13:46  Sandglass  阅读(1744)  评论(6编辑  收藏  举报