觀察者模式屬於行為型模式,定義了物件間的一對多依賴關係,當一個物件(主題/Subject)狀態改變時,所有依賴它的物件(觀察者/Observer)都會收到通知並自動更新。這是實現事件驅動架構、解耦發布者與訂閱者的經典模式。
AbstractMessageSubject)。MessageSubject)。IMessage)。SqlMessage, XmlMessage)。情境:當 MessageModel 發生變更(如發布時間更新),自動通知 SQL 與 XML 兩個通道執行插入操作。
// 觀察者介面
public interface IMessage
{
string Insert(MessageModel mm);
}
// SQL 觀察者
public class SqlMessage : IMessage
{
public string Insert(MessageModel mm) => $"sql方式:{mm.Message} {mm.PublishTime}";
}
// XML 觀察者
public class XmlMessage : IMessage
{
public string Insert(MessageModel mm) => $"xml方式:{mm.Message} {mm.PublishTime}";
}
using System.Collections.Generic;
public abstract class AbstractMessageSubject
{
private readonly MessageModel _model;
private readonly List<IMessage> _observers = new List<IMessage>();
protected AbstractMessageSubject(MessageModel mm) { _model = mm; }
public void Attach(IMessage observer) => _observers.Add(observer);
public void Detach(IMessage observer) => _observers.Remove(observer);
public string Notify()
{
var result = string.Empty;
foreach (var obs in _observers)
{
result += obs.Insert(_model) + "<br />";
}
return result;
}
// 當 PublishTime 變更時自動通知
public DateTime PublishTime
{
get => _model.PublishTime;
set
{
_model.PublishTime = value;
Notify(); // 狀態改變觸發通知
}
}
}
public class MessageSubject : AbstractMessageSubject
{
public MessageSubject(MessageModel mm) : base(mm) { }
}
public partial class Observer : Page
{
protected void Page_Load(object sender, EventArgs e)
{
var subject = new MessageSubject(new MessageModel("插入Message", DateTime.Now));
var sqlObs = new SqlMessage();
var xmlObs = new XmlMessage();
subject.Attach(sqlObs);
subject.Attach(xmlObs);
// 手動觸發通知 (或透過修改 PublishTime 自動觸發)
Response.Write(subject.Notify());
// 若取消註解下行,將再次觸發通知
// subject.PublishTime = DateTime.Now;
}
}
sql方式:插入Message 2007-5-26 9:38:18
xml方式:插入Message 2007-5-26 9:38:18
在現代 C# 開發中,觀察者模式通常直接使用內建的 event 與 delegate 機制,或 IObservable<T>/IObserver<T> (Reactive Extensions) 來實現,提供更優雅的語法與執行緒安全保障。但理解經典模式結構有助於掌握事件驅動架構的本質。
| 優點 | 缺點 |
|---|---|
| 主題與觀察者鬆耦合 | 觀察者過多時通知效能可能下降 |
| 支援廣播通訊 | 可能導致循環引用或記憶體洩漏 (需正確移除) |
| 符合開放封閉原則 | 若觀察者邏輯複雜,除錯困難 |