观察者模式
前言
观察者模式又叫发布-订阅(Publish/Subscribe)模式
观察者模式定义了一种一对多的依赖关系,让多个观察者对象同时监听某一个主题对象。这个主题对象在状态发生变化时,会通知所有观察者,使它们能够自己更新自己。
一、观察者模式
1、subject类,它吧所有对观察者对象的引用保存在一个聚集里,每个主题都可以有任何数量的观察者,抽象主题提供一个借口,可以增加和删除观察者对象。
1 /// <summary>
2 /// 主题或抽象通知者
3 /// </summary>
4 public abstract class Subject
5 {
6 //同事列表
7 private IList<Observer> observers = new List<Observer>();
8
9 //增加
10 public void Attach(Observer observer)
11 {
12 observers.Add(observer);
13 }
14 //减少
15
16 public void Detach(Observer observer)
17 {
18 observers.Remove(observer);
19
20 }
21 //通知
22 public void Notify()
23 {
24 foreach (var i in observers)
25 i.Update();
26 }
27 }
2、Observer类,抽象观察者,为所有具体观察者定义一个借口,在得到主题的通知时更新自己。抽象观察者一般用一个抽象类或者一个接口实现。
1 //抽象观察者
2 public abstract class Observer
3 {
4 public abstract void Update();
5 }
3、ConcreteObserver类,具体观察者,实现抽象观察者角色所要求的更新接口,以便使本身的状态与主题的状态相协调。
1 public class ConcreteObserver : Observer
2 {
3 private string name;
4 private string observerState;
5 private ConcreteSubject subject;
6 public ConcreteObserver(ConcreteSubject subject,string name)
7 {
8 this.name = name;
9 this.subject = subject;
10 }
11
12 public override void Update()
13 {
14 observerState = subject.SubjectState;
15 Console.WriteLine("观察者{0}的新状态是{1}", name, observerState);
16 }
17 public ConcreteSubject Subject
18 {
19 get { return subject; }
20 set { subject = value; }
21 }
22 }
4、具体主题或具体通知者,将有关状态存入具体观察者对象;在具体主题内部状态改变时,给所有登记过的观察者发出通知。
1 public class ConcreteSubject:Subject
2 {
3
4 private string action;
5 //前台状态
6 public string SubjectState
7 {
8 get { return action; }
9 set { action = value; }
10 }
11 }
5、客户端
1 class Program
2 {
3 static void Main(string[] args)
4 {
5 #region 抽象模式
6 ConcreteSubject s = new ConcreteSubject();
7
8 s.Attach(new ConcreteObserver(s, "X"));
9 s.Attach(new ConcreteObserver(s, "Y"));
10 s.Attach(new ConcreteObserver(s, "Z"));
11
12 s.SubjectState = "ABC";
13 //发出通知
14 s.Notify();
15
16 #endregion
17
18 Console.ReadKey();
19 }
20 }
总结
1、当一个对象的改变需要同时改变其他对象时,而且不需要知道具体有对少对象有改变,应考虑使用观察者模式。
2、当一个抽象模型有两个方面,其中一个方面依赖于另一个方面,这时用观察者模式可以将这两者封装在独立的对象中使它们各自独立地改变和复用。
3、观察者模式所做的工作其实就是在解耦。让耦合的双方都依赖于抽象,而不依赖于具体,从而使得各自的变化都不会影响另一边的变化。这时依赖倒转原则的最佳体现。
4、缺点:尽管已经用了依赖倒转原则,但是“抽象通知者”还是依赖“抽象观察者”,另外每个具体观察者,它不一定是“更新”的方法要调用
二、事件委托实现
1、观察者
1 public class StockObserver
2 {
3 private string name;
4 private string observerState;
5 private Subject subject;
6 public StockObserver(Subject subject, string name)
7 {
8 this.name = name;
9 this.subject = subject;
10 }
11 public void CloseStockMarket()
12 {
13 Console.WriteLine("{0}{1} 关闭股票行情,继续工作!",subject.SubjectState,name);
14 }
15 }
16 public class NBAObserver
17 {
18 private string name;
19 private string observerState;
20 private Subject subject;
21 public NBAObserver(Subject subject, string name)
22 {
23 this.name = name;
24 this.subject = subject;
25 }
26 public void CloseNBA()
27 {
28 Console.WriteLine("{0}{1} 关闭NBA直播,继续工作!", subject.SubjectState, name);
29 }
30 }
2、抽象通知者
1 public interface Subject
2 {
3 void Notify();
4 string SubjectState { get; set; }
5 }
3、具体通知者
1 //声明一个委托,名称叫“EventHandler(事件处理程序)”,无参数,无返回值
2 public delegate void EventHandler();
3 public class Boss : Subject
4 {
5 //声明一事件Update,类型为委托EventHandler
6 public event EventHandler Update;
7 private string action;
8 public string SubjectState
9 {
10 get
11 {
12 return action;
13 }
14
15 set
16 {
17 action = value;
18 }
19 }
20 //在访问“通知”方法时,调用“更新”
21 public void Notify()
22 {
23 Update();
24 }
25 }
4、客户端
1 class Program
2 {
3 static void Main(string[] args)
4 {
5 Boss huhansan = new Boss();
6 //看股票的同事
7 StockObserver tong1 = new StockObserver(huhansan,"小美");
8
9 //看NBA的同事
10 NBAObserver tong2 = new NBAObserver(huhansan, "小花");
11
12
13 huhansan.Update += new EventHandler(tong1.CloseStockMarket);
14 huhansan.Update += new EventHandler(tong2.CloseNBA);
15 //老板回来
16 huhansan.SubjectState = "我胡汉三回来了";
17 //通知
18 huhansan.Notify();
19
20 Console.ReadKey();
21 }
22 }
总结
1、委托就是一种引用方法的类型。一旦为委托分配了方法,委托将于该方法具体完全相同的行为。
2、委托方法的使用可以像其他任何方法一样,具有参数和返回值。
3、委托可以看作是对函数的抽象,是函数的‘类’,委托的实例将代表一个具体的函数。
4、委托对象所搭载的所有方法必须具有相同的原形和形式,也就是拥有相同的参数列表和返回值类型。
参考书籍:大话设计模式