又稱發布-訂閱、模型-視圖、源-監聽器模式。定義一對多依賴:多個觀察者同時監聽一個主題,主題狀態變化時自動通知所有觀察者更新。為實現低耦合下的高協作,觀察者模式是關鍵方案。

Update())。Notify()。主題面向抽象觀察者編程,動態維護觀察者列表,實現鬆耦合。
// Observer pattern -- Structural example
using System; using System.Collections;
abstract class Subject {
private ArrayList observers = new ArrayList();
public void Attach(Observer o) { observers.Add(o); }
public void Detach(Observer o) { observers.Remove(o); }
public void Notify() { foreach (Observer o in observers) o.Update(); }
}
class ConcreteSubject : Subject {
private string subjectState;
public string SubjectState { get { return subjectState; } set { subjectState = value; } }
}
abstract class Observer { abstract public void Update(); }
class ConcreteObserver : Observer {
private string name, observerState; private ConcreteSubject subject;
public ConcreteObserver(ConcreteSubject s, string n) { subject = s; name = n; }
public override void Update() {
observerState = subject.SubjectState;
Console.WriteLine("Observer {0}'s new state is {1}", name, observerState);
}
public ConcreteSubject Subject { get { return subject; } set { subject = value; } }
}
public class Client {
public static void Main() {
ConcreteSubject s = new ConcreteSubject();
s.Attach(new ConcreteObserver(s, "1"));
s.Attach(new ConcreteObserver(s, "2"));
s.Attach(new ConcreteObserver(s, "3"));
s.SubjectState = "ABC"; s.Notify();
}
}
.NET 原生委託/事件機制可大幅簡化觀察者模式:
// Observer pattern -- Structural example (Delegate/Event)
using System;
delegate void UpdateDelegate();
class Subject {
public event UpdateDelegate UpdateHandler;
public void Attach(UpdateDelegate ud) { UpdateHandler += ud; }
public void Detach(UpdateDelegate ud) { UpdateHandler -= ud; }
public void Notify() { if (UpdateHandler != null) UpdateHandler(); }
}
class ConcreteSubject : Subject {
private string subjectState;
public string SubjectState { get { return subjectState; } set { subjectState = value; } }
}
class ConcreteObserver {
private string name, observerState; private ConcreteSubject subject;
public ConcreteObserver(ConcreteSubject s, string n) { subject = s; name = n; }
public void Update() {
observerState = subject.SubjectState;
Console.WriteLine("Observer {0}'s new state is {1}", name, observerState);
}
public ConcreteSubject Subject { get { return subject; } set { subject = value; } }
}
class AnotherObserver {
public void Show() { Console.WriteLine("AnotherObserver got an Notification!"); }
}
public class Client {
public static void Main() {
ConcreteSubject s = new ConcreteSubject();
ConcreteObserver o1 = new ConcreteObserver(s, "1"), o2 = new ConcreteObserver(s, "2");
AnotherObserver o3 = new AnotherObserver();
s.Attach(new UpdateDelegate(o1.Update));
s.Attach(new UpdateDelegate(o2.Update));
s.Attach(new UpdateDelegate(o3.Show)); // 任意符合簽名的方法均可訂閱
s.SubjectState = "ABC"; s.Notify();
Console.WriteLine("--------------------------");
s.Detach(new UpdateDelegate(o1.Update));
s.SubjectState = "DEF"; s.Notify();
}
}
關鍵點: 委託規範方法簽名;事件封裝委託多播;+=/-= 訂閱/退訂;Invoke() 廣播通知。
// Observer pattern -- Real World example
using System; using System.Collections;
abstract class Stock {
protected string symbol; protected double price;
private ArrayList investors = new ArrayList();
public Stock(string symbol, double price) { this.symbol = symbol; this.price = price; }
public void Attach(Investor i) { investors.Add(i); }
public void Detach(Investor i) { investors.Remove(i); }
public void Notify() { foreach (Investor i in investors) i.Update(this); }
public double Price {
get { return price; }
set { price = value; Notify(); } // 價格變更自動通知
}
public string Symbol { get { return symbol; } set { symbol = value; } }
}
class IBM : Stock { public IBM(string s, double p) : base(s, p) {} }
interface IInvestor { void Update(Stock stock); }
class Investor : IInvestor {
private string name; private Stock stock;
public Investor(string n) { name = n; }
public void Update(Stock s) {
Console.WriteLine("Notified investor {0} of {1}'s change to {2:C}", name, s.Symbol, s.Price);
}
public Stock Stock { get { return stock; } set { stock = value; } }
}
public class ObserverApp {
public static void Main() {
Investor s = new Investor("Sorros"), b = new Investor("Berkshire");
IBM ibm = new IBM("IBM", 120.00);
ibm.Attach(s); ibm.Attach(b);
ibm.Price = 120.10; ibm.Price = 121.00; ibm.Price = 120.50; ibm.Price = 120.75;
}
}
優點:
缺點: