Subject (介面) Observer (介面)
▲ ▲
│ │
ConcreteSubject ConcreteObserver
- observers: List - subject: Subject
- Attach/Detach - Update()
- Notify()
using System;
using System.Collections;
namespace ObserverGoF
{
// 1. 觀察者介面
public interface IObserver
{
void Update(int number);
}
// 2. 主題介面
public interface ISubject
{
void Attach(IObserver observer);
void Detach(IObserver observer);
void Notify();
}
// 3. 具體主題
public class Subject : ISubject
{
private ArrayList _observers = new ArrayList();
private int _state;
public int State
{
get => _state;
set
{
_state = value;
Notify(); // 狀態變更自動通知
}
}
public void Attach(IObserver observer) => _observers.Add(observer);
public void Detach(IObserver observer) => _observers.Remove(observer);
public void Notify()
{
foreach (IObserver o in _observers)
o.Update(_state);
}
}
// 4. 具體觀察者 A
public class ObserverA : IObserver
{
public void Update(int number)
{
Console.WriteLine($"[ObserverA] 收到狀態變更:{number}");
}
}
// 5. 具體觀察者 B
public class ObserverB : IObserver
{
private string _name;
public ObserverB(string name) => _name = name;
public void Update(int number)
{
Console.WriteLine($"[{_name}] 處理數字:{number * 2}");
}
}
// 6. 用戶端
class Program
{
static void Main()
{
var subject = new Subject();
subject.Attach(new ObserverA());
subject.Attach(new ObserverB("ObserverB"));
Console.WriteLine("設定狀態 = 10");
subject.State = 10;
Console.WriteLine("\n設定狀態 = 20");
subject.State = 20;
Console.ReadKey();
}
}
}
| 維度 | GoF 介面式 | .NET Event/Delegate |
|---|---|---|
| 型別安全 | 需轉型或泛型介面 | 原生強型別 |
| 多播支援 | 手動管理清單 | 內建 +=/-= |
| 語法簡潔度 | 較繁瑣 | 語言級關鍵字 |
| 序列化/遠端 | 易於序列化傳遞 | 事件不可序列化 |
| 適用場景 | 跨語言、需持久化訂閱關係 | 一般 .NET 內部事件驅動 |
public interface IObserver { void OnNext(T value); }
public interface ISubject
{
IDisposable Subscribe(IObserver observer);
// 回傳 IDisposable 方便取消訂閱 (Rx 風格)
}
public class EventSubject : ISubject
{
private readonly List> _observers = new();
public IDisposable Subscribe(IObserver observer)
{
_observers.Add(observer);
return new Unsubscriber(_observers, observer);
}
public void Notify(T value) => _observers.ForEach(o => o.OnNext(value));
private sealed class Unsubscriber : IDisposable
{
private List> _list; private IObserver _obs;
public Unsubscriber(List> list, IObserver obs) => (_list, _obs) = (list, obs);
public void Dispose() => _list?.Remove(_obs);
}
}
GoF 介面式觀察者模式雖較繁瑣,但概念純粹、跨平台通用、易於序列化與單元測試。在 .NET 生態系內,優先使用 `event`/`delegate`;需跨進程、跨語言、或建構類 Rx 流式處理管線時,介面式設計更具彈性。