一、概述:
定義對象間的一種一對多的依賴關系,當一個對象的狀態發生改變時, 所有依賴於它的對象都得到通知並被自動更新。[GOF 《設計模式》]
看了Terrylee的.NET設計模式(19):觀察者模式(Observer Pattern),個人認為其模式的推導比較清晰,但感覺舉的例子不是很好,和實際項目還是有些脫離。正好手上有一小項目應用了此模式,不知應用的是否正確,如果理解的不到位,請大家指正。此文算是對.NET設計模式(19):觀察者模式(Observer Pattern)的一個補充吧,不知Terrylee是否允許。
二、觀察者模式結構圖:
三、實際列子:
一監控系統,需要根據系統某些變化報警,報警方式有Email、短信等多種,以後可能會變化。怎麼演繹到觀察者模式就不再多說了(如果需要的話再補充,一般參考Terrylee的文章即可明白)。
IAlarm是報警接口。當我們的系統需要添加報警方式的時候只需實現IAlarm的Warn方法即可。Email類是Email報警的實現,SMS類是短信報警的實現。
MonitorContainer是監視器(抽象類)相當於觀察者。只負責通知變化,當子類調用Notify方法它即會通知報警模塊報警,如Email和SMS(短信)。
NetMonitor是其中的具體的監控模塊,繼承於MonitorContainer。當發現系統網絡有問題時會調用父類的Notify方法。
MonitorContainer裡的AddAlarm這裡就省略了(把報警模塊對象加入到ArraryList中)
Notify方法就是foreach下報警模塊對象集合。(可參考.NET設計模式(19):觀察者模式(Observer Pattern)文章裡的代碼)
NetMonitor的調用代碼:
Pulbic class NetMonitor
{
Public void Monitor()
{
MonitorContaniner netMonitor = new NetMonitor();
IAlarm mailAlarm = new EmailAlarm();
netMonitor. AddAlarm (mailAlarm);//增加Eamil報警模塊
IAlarm smsAlarm = new SMSAlarm();
netMonitor. AddAlarm (smsAlarm);//增加SMS報警模塊
base.Notify();
}
}
個人感覺各個模塊間藕合的還是比較厲害。怎麼辦?於是我加入了IOC。我使用的是Castle的IOC容器。
MonitorContainer具體代碼:
/**//// <summary>
/// 監控模塊容器
/// </summary>
public abstract class MontiorContainer
{
private statci IWindsorContainer container = null;
private string _alarmMessage;
statci MontiorContainer ()
{
container = new WindsorContainer("Alarm.xml");//報警器的設置文件
}
}
public void Notify()
{
if (container != null)
{
IConfiguration[] configuration = container.Kernel.ConfigurationStore.GetComponents();
foreach (IConfiguration item in configuration)//依次調用報警模塊
{
//framework 1.1
IAlarm alarm = container.Resolve(item.Attributes["id"].ToString()) as IAlarm ;
//framework2可以使用
//IAlarm alarm = container.Resolve<IAlarm >(item.Attributes["id"].ToString());
alarm.Warn(_alarmMessage);
}
}
}
//擴展:如果需要根據監控情況而采取不同的報警方式,對應的需要修改Instance
/**//*public void RemoveAlarm()
{
}
public void AddAlarm(string alarmType)
{
}*/
//報警內容
public string AlarmMessage
{
set{ _alarmMessage = value;}
}
Alarm.xml(Castle的標准配置)
<?xml version="1.0" encoding="utf-8" ?>
<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的調用代碼:
Pulbic class NetMonitor
{
Public void Monitor()
{
base.Notify();
}
}
怎麼樣,簡單吧。把藕合度大大降低了。
四、總結
通過Observer模式結合IOC容器,把一對多對象之間的通知依賴關系的變得更為松散,大大地提高了程序的可維護性和可擴展性。
擴展報警模塊不需對現有系統代碼修改即可增加,具體的監控模塊都不需知道怎麼調用報警模塊。