.NET 內建機制可大幅簡化傳統介面式觀察者實作。
// 1. 定義委派規範方法簽章
delegate void UpdateDelegate();
// 2. 主題類別定義事件
public event UpdateDelegate UpdateHandler;
// 3. 訂閱事件
public void Attach(UpdateDelegate ud) => UpdateHandler += ud;
public void Detach(UpdateDelegate ud) => UpdateHandler -= ud;
// 4. 觸發通知
public void Notify()
{
if (UpdateHandler != null) UpdateHandler();
}
ConcreteSubject s = new ConcreteSubject();
ConcreteObserver o1 = new ConcreteObserver(s, "1");
ConcreteObserver o2 = new ConcreteObserver(s, "2");
AnotherObserver o3 = new AnotherObserver();
// 訂閱:任何符合 UpdateDelegate 簽章的方法皆可
s.Attach(new UpdateDelegate(o1.Update));
s.Attach(new UpdateDelegate(o2.Update));
s.Attach(new UpdateDelegate(o3.Show)); // 方法名可不同!
s.SubjectState = "ABC";
s.Notify();
s.Detach(new UpdateDelegate(o1.Update)); // 取消訂閱
s.SubjectState = "DEF";
s.Notify();
| 傳統介面式 | Delegate/Event |
|---|---|
| 強制實作 Update() 方法 | 任何符合簽章的方法皆可 |
| 單一介面限制 | 同一事件可綁定不同類別的不同方法 |
| 手動管理觀察者清單 | 事件自動管理調用列表 |
| 鬆耦合但代碼較繁瑣 | 語言原生支援,語法簡潔 |
// 傳統介面式實作(留給讀者練習轉換為 Event 版本)
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 investor) => investors.Add(investor);
public void Detach(Investor investor) => investors.Remove(investor);
public void Notify()
{
foreach (Investor i in investors) i.Update(this);
}
public double Price
{
get => price;
set { price = value; Notify(); } // 價格變動自動通知
}
}
class IBM : Stock { public IBM(string s, double p) : base(s, p) { } }
interface IInvestor { void Update(Stock stock); }
class Investor : IInvestor
{
private string name;
public Investor(string name) => this.name = name;
public void Update(Stock stock)
{
Console.WriteLine($"Notified investor {name} of {stock.Symbol}'s change to {stock.Price:C}");
}
}
// 測試
public class ObserverApp
{
public static void Main()
{
Investor s = new Investor("Sorros");
Investor 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;
}
}
Notified investor Sorros of IBM's change to $120.10 Notified investor Berkshire of IBM's change to $120.10 Notified investor Sorros of IBM's change to $121.00 Notified investor Berkshire of IBM's change to $121.00 Notified investor Sorros of IBM's change to $120.50 Notified investor Berkshire of IBM's change to $120.50 Notified investor Sorros of IBM's change to $120.75 Notified investor Berkshire of IBM's change to $120.75