zoukankan      html  css  js  c++  java
  • 设计模式——观察者模式

      观察者模式——定义了一种一对多的依赖关系,让多个观察者对象同时监听某一个主题对象,这个主题对象在状态发生改变时,会通知所有观察者对象,使它们能够自动更新自己。

      观察者模式正如以上定义所说的,为了解决一个对象的状态改变,同时去改变另外几个对象的状态的一个设计模式。当然,那些观察者必须保持一致。

    1.Subject类,抽象通知者类,定义并且实现了增加观察者,移除观察者,和通知观察者的方法。

     1 /// <summary>
     2 /// 抽象通知者
     3 /// </summary>
     4 public abstract class Subject
     5 {
     6     //定义一个观察者对象
     7     private readonly IList<Observer> _observers = new List<Observer>();
     8 
     9     /// <summary>
    10     /// 增加观察者
    11     /// </summary>
    12     /// <param name="observer">观察者</param>
    13     public void Attach(Observer observer)
    14     {
    15         _observers.Add(observer);
    16     }
    17 
    18     /// <summary>
    19     /// 移除观察者
    20     /// </summary>
    21     /// <param name="observer">观察者</param>
    22     public void Detach(Observer observer)
    23     {
    24         _observers.Remove(observer);
    25     }
    26 
    27     /// <summary>
    28     /// 进行通知
    29     /// </summary>
    30     public void Notify()
    31     {
    32         foreach (var observer in _observers)
    33         {
    34             observer.Update();
    35         }
    36     }
    37 }
    Subject.cs

    2.ConcreteSubject类,定义了通知者的状态属性

    1 /// <summary>
    2 /// 具体通知者
    3 /// </summary>
    4 public class ConcreteSubject : Subject
    5 {
    6     //被观察的状态
    7     public string SubjectState { get; set; }
    8 }
    ConcreteSubject.cs

    3.Observer类,抽象观察者类,定义了观察者更新状态的抽象方法

    Observer.cs

    4.ConcreteObserver类,具体的观察者类,根据构造方法得到通知者的状态改变,并进行跟新操作

     1 /// <summary>
     2 /// 具体观察者
     3 /// </summary>
     4 public class ConcreteObserver : Observer
     5 {
     6     /// <summary>
     7     /// 观察者名字
     8     /// </summary>
     9     private readonly string _name;
    10 
    11     /// <summary>
    12     /// 观察者状态
    13     /// </summary>
    14     private string _observerState;
    15 
    16 
    17     private ConcreteSubject _concreteSubject;
    18     /// <summary>
    19     /// 通知者对象
    20     /// </summary>
    21     public ConcreteSubject ConcreteSubject
    22     {
    23         get { return _concreteSubject; }
    24         set { _concreteSubject = value; }
    25     }
    26 
    27     /// <summary>
    28     /// 具体观察者构造方法
    29     /// </summary>
    30     /// <param name="subject">通知者对象</param>
    31     /// <param name="name">观察者姓名</param>
    32     public ConcreteObserver(ConcreteSubject subject, string name)
    33     {
    34         _concreteSubject = subject;
    35         _name = name;
    36     }
    37 
    38     /// <summary>
    39     /// 状态更新
    40     /// </summary>
    41     public override void Update()
    42     {
    43         _observerState = _concreteSubject.SubjectState;
    44         Console.Write("观察者{0}的新状态是{1}", _name, _observerState);
    45     }
    46 }
    ConcreteObserver.cs

    5.客户端代码,实例化通知者,并且添加观察者,改变通知者状态,观察者一起更新

     1 class Program
     2 {
     3     static void Main(string[] args)
     4     {
     5 
     6         var subject = new ConcreteSubject();
     7 
     8         subject.Attach(new ConcreteObserver(subject, "X"));
     9 
    10         subject.Attach(new ConcreteObserver(subject, "Y"));
    11 
    12         subject.SubjectState = "123";
    13 
    14         subject.Notify();
    15     }
    16 }
    Program.cs

      以上的观察者模式是实现了一个状态改变,观察者状态改变。但是有一个缺点,那就是一个通知,所有的观察者的状态都改变了,而且改变的都一样,这样在实际开发中是很少遇见的,我们不希望为了维持一致性而使各类紧密耦合,这样会给维护和复用都带来不便。

      所以,下面我们需要对观察者模式进行改进,会用.NET中一个特殊方法,那就是事件委托。

      委托——委托就是一种引用方法的类型。一旦为委托分配了方法,委托将于该方法具有完全相同的行为。委托方法的使用可以像其他任何方法一样,具有参数和返回值。委托可以看作是对方法的抽象,是函数的“类”,委托的实例将代表一个具体的方法。

      委托可以搭载多个方法,所有方法将被依次唤醒,委托所搭载的方法并不需要属于同一个类,只要参数和返回值类型一致就行了。

    1.ISubject接口,定义了通知者的通知方法和状态属性

     1 /// <summary>
     2 /// 通知者接口
     3 /// </summary>
     4 public interface ISubject
     5 {
     6     /// <summary>
     7     /// 进行通知
     8     /// </summary>
     9     void Notify();
    10 
    11     /// <summary>
    12     /// 通知者状态
    13     /// </summary>
    14     string SubjectState { get; set; }
    15 }
    ISubject.cs

    2.Observer类,具体的观察者类,自身有不同的更新方法,但是参数和返回值一致,实现了什么可以不一致

     1 /// <summary>
     2 /// 股票行情观察者
     3 /// </summary>
     4 public class StockObserver
     5 {
     6     private readonly string _name;
     7     private readonly ISubject _subject;
     8 
     9     
    10     public StockObserver(string mame, ISubject subject)
    11     {
    12         _name = mame;
    13         _subject = subject;
    14     }
    15 
    16     /// <summary>
    17     /// 原Update方法
    18     /// 先改成具体的差异化动作
    19     /// </summary>
    20     public void CloseStockMarket()
    21     {
    22         Console.WriteLine("{0}{1}关闭股票行情,继续工作", _subject.SubjectState, _name);
    23     }
    24 }
    25 
    26 /// <summary>
    27 /// NBA直播观察者
    28 /// </summary>
    29 public class NBAObserver
    30 {
    31     private readonly string _name;
    32     private readonly ISubject _subject;
    33 
    34     public NBAObserver(string mame, ISubject subject)
    35     {
    36         _name = mame;
    37         _subject = subject;
    38     }
    39 
    40     /// <summary>
    41     /// 原Update方法
    42     /// 先改成具体的差异化动作
    43     /// </summary>
    44     public void CloseNBADirectSeeding()
    45     {
    46         Console.WriteLine("{0}{1}关闭NBA直播,继续工作", _subject.SubjectState, _name);
    47     }
    48 }
    Observer.cs

    3.Subject类,具体的通知者,实现了接口的通知方法和状态属性,并且定义了一个委托,可以搭载各个观察者的更新需求

     1 /// <summary>
     2 /// 定义一个委托
     3 /// 委托上的任务是给观察者通知
     4 /// </summary>
     5 public delegate void EventHandeler();
     6 
     7 /// <summary>
     8 /// 通知者,实现通知接口
     9 /// </summary>
    10 public class Boss : ISubject
    11 {
    12     /// <summary>
    13     /// 实例化委托
    14     /// </summary>
    15     public event EventHandeler Update;
    16 
    17     /// <summary>
    18     /// 调用委托方法去进行通知
    19     /// 委托可以使委托链
    20     /// 那么可以同时实现多种通知
    21     /// </summary>
    22     public void Notify()
    23     {
    24         Update();
    25     }
    26 
    27     /// <summary>
    28     /// 实现接口的通知状态属性
    29     /// </summary>
    30     public string SubjectState { get; set; }
    31 }
    32 
    33 public class Secretary : ISubject
    34 {
    35     public event EventHandeler Update;
    36 
    37     public void Notify()
    38     {
    39         Update();
    40     }
    41 
    42     string ISubject.SubjectState { get; set; }
    43 }
    Subject.cs

    4.客户端代码,创建通知者对象,并创建观察者对象,将观察者的更新需求搭载进通知者的委托链,然后改变通知者的状态,发出通知,观察者进行自我更新

     1 class Program
     2 {
     3     static void Main(string[] args)
     4     {
     5         //创建通知者老板
     6         var boss = new Boss();
     7 
     8         //创建具体的观察者同事
     9 
    10         var colleague1 = new StockObserver("张三 ", boss);
    11 
    12         var colleague2 = new NBAObserver("李四 ", boss);
    13 
    14         //给通知者添加通知的事件
    15         boss.Update+=new EventHandeler(colleague1.CloseStockMarket);
    16         boss.Update+=new EventHandeler(colleague2.CloseNBADirectSeeding);
    17 
    18         //老板回来了,状态更改
    19         boss.SubjectState = "我胡汉三又回来啦,";
    20         //老板作为通知者通知观察者
    21         boss.Notify();
    22         Console.ReadKey();
    23 
    24     }
    25 }
    Program.cs

                                                         以上内容部分参考程杰的《大话设计模式》一书

  • 相关阅读:
    欠采样和过采样
    分类模型之K近邻算法
    机器学习之分类模型
    。。。
    等人
    习惯
    六月一日
    回首
    你还年轻他们老了
    C#和JavaScript交互(asp.net前台和后台互调)总结 (转)
  • 原文地址:https://www.cnblogs.com/Smilodon/p/3100433.html
Copyright © 2011-2022 走看看