一、概述:
定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时, 所有依赖于它的对象都得到通知并被自动更新。[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的调用代码:
{
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>
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的调用代码:
{
Public void Monitor()
{
base.Notify();
}
}
怎么样,简单吧。把藕合度大大降低了。
四、总结
通过Observer模式结合IOC容器,把一对多对象之间的通知依赖关系的变得更为松散,大大地提高了程序的可维护性和可扩展性。
扩展报警模块不需对现有系统代码修改即可增加,具体的监控模块都不需知道怎么调用报警模块。