• 设计模式之观察者模式


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

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

    总结: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图如下:

     

    一个完整的人生应该是宽恕、容忍、等待和爱!
  • 相关阅读:
    SUM游戏
    指针入门(四)
    MSP430 G2553 寄存器列表与引脚功能
    MSP430G2553头文件解析
    修复Kaos的中文显示
    VIM使用技巧3
    VIM使用技巧2
    Java学习之路(3)
    指针入门(三)
    共享VIM配置文件
  • 原文地址:https://www.cnblogs.com/homezzm/p/1615279.html
Copyright © 2020-2023  润新知