觀察者模式定義物件間一對多依賴,主題狀態變更時自動通知所有觀察者。結合 IOC 容器可進一步消除硬編碼依賴,大幅提升擴充性。本文以監控報警系統為例說明。

介面 IAlarm 定義 Warn 方法。EmailAlarm、SMSAlarm 實作介面。抽象類別 MonitorContainer 維護報警器清單,提供 AddAlarm/Notify。具體監控類別 NetMonitor 繼承 MonitorContainer,發現問題時呼叫 base.Notify()。

public class NetMonitor
{
public void Monitor()
{
MonitorContainer netMonitor = new NetMonitor();
netMonitor.AddAlarm(new EmailAlarm());
netMonitor.AddAlarm(new SMSAlarm());
base.Notify();
}
}
缺點:監控類別需直接 new 具體報警類別,耦合度高,新增報警方式需修改程式碼。
將報警器註冊至 XML 設定檔,容器啟動時自動載入。MonitorContainer 改為從容器解析所有 IAlarm 實作:
public abstract class MonitorContainer
{
private static IWindsorContainer container = null;
private string _alarmMessage;
static MonitorContainer()
{
container = new WindsorContainer("Alarm.xml");
}
public void Notify()
{
if (container != null)
{
var configurations = container.Kernel.ConfigurationStore.GetComponents();
foreach (var item in configurations)
{
IAlarm alarm = container.Resolve(item.Attributes["id"].ToString()) as IAlarm;
alarm.Warn(_alarmMessage);
}
}
}
public string AlarmMessage { set { _alarmMessage = value; } }
}
Alarm.xml:
<configuration>
<components>
<component id="EmailAlarm" service="Alarm.IAlarm,IAlarm" type="Alarm.EMailAlarm,EMailAlarm"/>
<component id="SMSIAlarm" service="Alarm.IAlarm,IAlarm" type="Alarm.SMSAlarm,SMSAlarm"/>
</components>
</configuration>
此時 NetMonitor 只需呼叫 base.Notify(),完全不需知道具體報警類別。
觀察者模式 + IOC 容器,將一對多通知依賴徹底解耦。擴充報警管道只需新增實作類別與 XML 設定,既有程式碼零修改,完美符合開放封閉原則。