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

观察者模式结构图:

观察者模式 - Observer_观察者模式

Subject 类,可以翻译为主题或抽象通知者,一般用一个抽象类或一个接口实现。它把所有对观察者对象的引用保存在一个集合里,每个主题都可以有任何数量的观察者。抽象主题提供一个接口,可以增加和删除观察者对象。
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()方法,这个方法叫做更新方法。
abstract class Observer
{
public abstract void Update();
}ConcreteSubject类,叫做具体主题或通知者,将有关状态存入具体观察者对象,在具体主题内部状态改变时,给所有登记过的观察者发出通知。具体主题角色通常用一个具体子类实现。
class ConcreteSubject : Subject
{
private string subjectState;
//具体被观察者状态
public string SubjectState
{
get { return subjectState;}
set { subjectState = value; }
}
}ConcreteObserver类,具体观察者,实现抽象观察者角色所要求的更新接口,以便使本身的状态与主题的状态相协调。具体观察者角色可以保存一个指向具体主题对象的引用。具体观察者通常用一个具体子类实现.
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;}
}
}---客户端代码---
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 ="ABS";
s.Notify(); Console.Read();
}观察者模式一般用在,当一个对象的改变需要同时改变其它对象,补充一下,而且它不知道具体有多少对象有待改变时,应该考虑用该模式。
观察者模式所做的工作其实就是在解除耦合,让耦合的双方都依赖于抽象,而不是依赖于具体,从而使得各自的变化都不影响另一边的变化。观察者模式的不足之处,尽管已经用了依赖倒转原则,但是‘抽象通知者’还是依赖抽象观察者,也就是说,万一没有了抽象观察者这样的接口,我这通知就完成不了,另外就是每个具体观察者,它不一定是‘更新’的方法要调用呀。如果通知者和观察者之间根本就互相不知道,由客户端来决定通知谁就好了
改进,用事件委托实现
看股票观察者类和看NBA观察者类去掉了父类抽象观察者类
//看股票的同事
class StockObserver
{
private string name;
private Subject sub;
public StockObserver(string name,Subject sub)
{
this.name = name;
this.sub = sub;
} //关闭股票行情 方法‘更新’名改为这个了
public void CloseStockMarket()
{
Console.WriteLine("{0} {1} 关闭股票行情,继续工作",sub.SubjectState,name);
}
}
//看NBA的同事
class NBAObserver
{

private string name;
private Subject sub;
public NBAObserver(string name,Subject sub)
{
this.name = name;
this.sub = sub;
} //关闭股票行情 方法‘更新’名改为这个了
public void CloseNBADirectSeeding()
{
Console.WriteLine("{0} {1} 关闭NBA直播继续工作",sub.SubjectState,name);
}
}现象中就是这样的,方法名本就不一定相同
抽象通知者,由于不希望依赖抽象观察者,所以增加,减少的方法也就没有必要了(抽象观察者已经不存在了)
//通知者接口
interface Subject
{
void Notify();
string SubjectState
{
get;
set;
}
}delegate void EventHandler();
前台秘书类
class Secretary : Subject
{
//声明一事件 Update,类型为委托EventHandler
public event EventHandler Update;
private string action; public void Notidy()
{
Update();
} public string SubjectState
{
get { return action;}
set { action = value;}
}
}---客户端代码---
static Main(string[] args)
{
Secretary mm = new Secretary();

StockObserver tongshi1 = new StockObserver("李同事",mm);
NBAObserver tongshi2 = new NBAObserver("姚同事",mm); mm.Update += new EventHandler(tongshi1.CloseStockMarket);
mm.Update += new EventHandler(tongshi2.CloseNABDirectSeeding); mm.SubjectState = "Boss 回来了";
mm.Notify(); Console.Read();
}

委托就是一种引用方法的类型,一旦为委托分配了方法,委托将与该方法具有完全相同的行为,委托方法的使用可以像其它任何方法一样,具有参数和返回值。委托可以看作是对函数的抽象,是函数的‘类’,委托的实例将代表一个具体的函数。
一个委托可以搭载多个方法,所有方法被依次唤起,更重要的是,它可以使得委托对象所搭载的方法并不需要同一个类。但委托也是有前提的,那就是委托对象所搭载的所有方法必须具有相同的原形和形式,也就是拥有相同的参数列表和返回值类型。