在一口一个设计模式--观察者模式中,我们已经知道如何应用观察者模式,但通过最近的深入学习,发现观察者模式存在以下缺陷:
1.抽象通知者依赖于抽象观察者;
2.每个具体观察者被调用的方法必须一致。
比如在机房收费系统中关于观察者模式的应用如下图所示:
这个设计存在以下问题:
1.抽象通知者需要把抽象观察者中的所有具体对象添加到集合中,以备向每个具体观察者发送通知消息;
2.在发送通知消息时,具体观察者中被通知的方法必须一致,否则具体通知者无法完成遍历;
3.更新卡内余额、更新学生上机状态和保存学生上机记录这三个类没什么相同的地方,抽象出来的抽象观察者有点牵强。
经过苦苦的思索,我发现用C#中的委托和事件机制解决上述问题,代码结构如下:
抽象通知者:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace 观察者模式_委托
{
public interface Informer
{
void Notify();
string Action { get; set; }
}
}
具体通知者--正常下机:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace 观察者模式_委托
{
public class Down : Informer
{
//声明一个委托
public delegate void EventHandler();
//为委托EventHandler添加事件Update
public event EventHandler Update;
public void Notify()
{
this.Update();
}
private string action;
public string Action
{
get { return action; }
set { action = value; }
}
}
}
具体通知者--强制下机:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace 观察者模式_委托
{
public class ForceDown : Informer
{
//声明一个委托
public delegate void EventHandler();
//为委托EventHandler添加事件Update
public event EventHandler Update;
public void Notify()
{
this.Update();
}
private string action;
public string Action
{
get { return action; }
set { action = value; }
}
}
}
这个我们不需要抽象观察者,直接具体观察者--更新卡内余额:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace 观察者模式_委托
{
public class UpdateBalance
{
protected Informer dn;
public UpdateBalance(Informer dn)
{
this.dn = dn;
}
public void ModifyBalance()
{
Console.WriteLine("{0}!该卡要下机,更新余额!", dn.Action);
}
}
}
具体观察者--更新学生上机状态:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace 观察者模式_委托
{
public class OffLine
{
protected Informer dn;
public OffLine(Informer dn)
{
this.dn = dn;
}
public void DelOnlineInfo()
{
Console.WriteLine("{0}!该卡要下机,删除正在上机表中的该卡信息!", dn.Action);
}
}
}
具体观察者--保存学生上机记录:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace 观察者模式_委托
{
public class SaveRec
{
protected Informer dn;
public SaveRec(Informer dn)
{
this.dn = dn;
}
public void SaveLineRec()
{
Console.WriteLine("{0}!该卡要下机,保存上机记录信息!", dn.Action);
}
}
}
main方法:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace 观察者模式_委托
{
class Program
{
static void Main(string[] args)
{
Down dn = new Down();
OffLine ol = new OffLine(dn);
UpdateBalance up = new UpdateBalance(dn);
SaveRec sr = new SaveRec(dn);
dn.Update+=new Down.EventHandler(ol.DelOnlineInfo);
dn.Update += new Down.EventHandler(up.ModifyBalance);
dn.Update += new Down.EventHandler(sr.SaveLineRec);
dn.Action = "刷卡下机";
dn.Notify();
}
}
}
程序执行结果如下所示:
通过执行结果,我们可以发现,在main方法中的正常下机事件dn.Update发生后,通过委托Down.EventHandler绑定到dn.Update事件上的三个方法ol.DelOnlineInfo、up.ModifyBalance、sr.SavelineRec都会被执行,达到观察者模式的效果。
现在我们可以发现:抽象通知者不再依赖于抽象观察者,因为抽象通知者通过委托通知具体观察者;具体观察者中被调用的方法也没必要一致,因为只需把想要执行的方法绑定到事件上就行;具体通知者也不必存在共性,不必牵强的对这三个类进行抽象。委托+事件完美解决上述问题。