观察者模式
Observer,又叫发布-订阅模式(Publish/Subscribe)。定义了一种一对多的依赖关系,让多个观察者对象同时监听某一个主题对象。这个主题对象在状态发生变化时,会通知所有观察者对象,使他们能够自动更新自己。
特点
将一个系统分割成一个一些类相互协作的类有一个不好的副作用,那就是需要维护相关对象间的一致性。我们不希望为了维持一致性而使各类紧密耦合,这样会给维护、扩展和重用都带来不便。
总之,观察者模式所做的工作其实就是在接触耦合,让耦合的双方都依赖与抽象,而不是依赖于具体。从而使得各自的变化都不会影响另一边的变化。
代码结构
结构图
角色
Subject类,主题或抽象通知者,提供一个接口,可以增加和删除观察者对象。
/// <summary>
/// 主题或抽象通知者
/// </summary>
abstract class Subject
{
private IList<Observer> observers = new List<Observer>();
//增加观察者
public void Attach(Observer observer)
{
observers.Add(observer);
}
//移除观察者
public void Detach(Observer observer)
{
observers.Remove(observer);
}
//通知
public void Notify()
{
foreach (Observer o in observers )
{
o.Update();
}
}
}
Observer类,抽象观察者,利用抽象接口更新自己,更新接口通常包含一个Update()方法。
/// <summary>
/// 抽象观察者
/// </summary>
abstract class Observer
{
public abstract void Update(); //更新方法
}
ConcreteSubject类,具体主题或通知者,将有关状态存入具体观察者对象;在具体主题的内部状态改变时,给所有登记过的观察者发出通知。
/// <summary>
/// 具体的主题(具体的通知者)
/// </summary>
class ConcreteSubject:Subject
{
private string subjectState;
//具体被观察者状态
public string SubjectState
{
get { return subjectState; }
set { subjectState = value; }
}
}
ConcreteObserver类,具体观察者,实现抽象观察者角色所要求的更新接口,以便使本身的状态与主题相协调。可以保存一个指向具体主题对象的引用,通常用一个具体子类实现。
/// <summary>
/// 具体观察者
/// </summary>
class ConcreteObserver:Observer
{
private string name;
private string observerState;
private ConcreteSubject subject;
public ConcreteObserver (ConcreteSubject subject,string name)
{
this.subject = subject;
this.name = name;
}
public override void Update()
{
observerState = subject.SubjectState;
Console.WriteLine("观察者{0}的新状态{1}", name, observerState);
}
public ConcreteSubject Subject
{
get { return subject; }
set { subject = value; }
}
}
客户端代码
class Program
{
static void Main(string[] args)
{
ConcreteSubject s = new ConcreteSubject();
s.Attach(new ConcreteObserver(s, "X"));
s.Attach(new ConcreteObserver(s, "Y"));
s.Attach(new ConcreteObserver(s, "Z"));
s.SubjectState = "ABC";
s.Notify();
Console.ReadKey();
}
}
结果显示
适用场景
1. 当一个对象的改变需要给变其它对象时,而且它不知道具体有多少个对象有待改变时。
2. 一个抽象某型有两个方面,当其中一个方面依赖于另一个方面,这时用观察者模式可以将这两者封装在独立的对象中使它们各自独立地改变和复用。
优点
观察者模式解除了主题和具体观察者的耦合,让耦合的双方都依赖于抽象,而不是依赖具体。从而使得各自的变化都不会影响另一边的变化。
完美的将观察者和被观察者分开,体现面向对象的一个原则: 系统中的每个类将重点放在某一个功能上,而不是其他方面。一个对象只做一件事情,并且将他做好。观察者模式在模块之间划定了清晰的界限,提高了应用程序的可维护性和重用性。
缺点
依赖关系并未完全解除,抽象通知者依旧依赖抽象的观察者。如果没有了抽象观察者这个接口,通知功能就不能完成。
如果通知者和观察者之间根本就互相不知道的,我们就需要通过客户端来决定通知谁,因而需要将通知事件委托给客户端。
事件委托
委托
是一种引用方法的类型,一旦为委托分配了方法,委托将与该方法具有完全相同的行为。委托方法的使用可以像其他任何方法一样,具有参数和返回值。委托可以看作是对函数的抽象,是函数的‘类’,委托的实例将代表一个具体的函数。
一个委托可以搭载多个方法,所有方法被一次唤起,并且可以使得委托对象所搭载的方法并不需要同一个类。
委托对象所搭载的所有方法必须具有相同的原形和形式,也就是拥有相同的参数列表和返回值列表。
语法
//声明一个特殊的类(委托类)
Delegate void EventHandler(); //EventHandler事件处理程序,无参数,无返回值
//声明类(委托类)的变量
例如:
Public event EventHandler Update;