设计模式——观察者模式

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

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

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

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

 

posted @ 2013-05-26 22:02  Kitten Zhang  阅读(148)  评论(0编辑  收藏  举报