Observer 观察者模式
2012-08-23 13:42 Mike.Jiang 阅读(568) 评论(0) 编辑 收藏 举报1 GOF中的定义
意图
定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时, 所有依赖于它的对象都得到通知并被自动更新。[GOF 《设计模式》]
结构图
2.概述
个人感觉观察者模式定义的比较不容易理解:什么多个观察者关注某个主题的,这个模式解决的是当一个对象需要调用一系列对象的方法时,并且是被调用方自己注册自己是否被调用,调用方不知道要调用哪些方法的问题。
3生活中的例子
现在,银行业务中有一项,当账号金额发生变化时就进行通知,默认是通知到手机,也可以选择将信息同时发送到邮箱。
4.调用方依赖被调用方
情景1:在这个业务的起初,账号金额变化,通知到手机
实现:
public class Account { public void AmountChange() { Phone phone = new Phone(); phone.Send(); } } public class Phone { public void Send() { Console.WriteLine("Send phone!"); } } static void Main(string[] args) { Account account = new Account(); account.AmountChange(); }
说明:在这里,Account是调用方(即所谓的主题),Phone是被调用方(所谓的观察者)。在这里调用方强依赖被调用方。
情景2:业务发展了,账号金额变化,即通知手机,也通知邮箱。
实现:
public class Account { public void AmountChange() { Phone phone = new Phone(); Email email = new Email(); phone.Send(); email.Send(); } } public class Email { public void Send() { Console.WriteLine("Send Email!"); } } public class Phone { public void Send() { Console.WriteLine("Send phone!"); } } static void Main(string[] args) { Account account = new Account(); account.AmountChange(); }
说明:在这里,新添加一个发送到邮箱的功能,必须要修改已有的Account类,违背了开放关闭原则。
5.调用方依赖接口,被调用方依赖接口(按照合约的设计)
情景3:重构情景2的代码
实现:
public class Account { IList<IObserver> oList = new List<IObserver>(); public void Attach(IObserver observer) { oList.Add(observer); } public void AmountChange() { foreach (IObserver observer in oList) { observer.SendNotify(); } } } public interface IObserver { void SendNotify(); } public class Phone : IObserver { public void SendNotify() { Console.WriteLine("Send phone!"); } } public class Email:IObserver { public void SendNotify() { Console.WriteLine("Send Email!"); } } static void Main(string[] args) { Account account = new Account(); Email email = new Email(); account.Attach(email); Phone phone = new Phone(); account.Attach(phone); account.AmountChange(); }
说明:在这里,调用方维护一个被调用方的列表,当需要调用被调用方时,只需要循环这个列表,即可;当新添加观察者时,只需要添加一个类继承IObserver接口,然后在客户端注册到IObserver列表中即可;
6.最后的重构(主动定阅)
情景4:在情景3中的实现,被调用方注册到调用列表的操作是在客户代码中实现的,被调用方被动注册,而在定义中被调用方是否被调用,是由被调用方自身决定,而不是调用方来决定。
实现:
public class Account { IList<IObserver> oList = new List<IObserver>(); public void Attach(IObserver observer) { oList.Add(observer); } public void AmountChange() { foreach (IObserver observer in oList) { observer.SendNotify(); } } } public interface IObserver { void SendNotify(); } public class Phone : IObserver { public Account subject; public Phone() { } public Phone(Account subject) { this.subject = subject; this.subject.Attach(this); } public void SendNotify() { Console.WriteLine("Send phone!"); } } public class Email : IObserver { public Account subject; public Email() { } public Email(Account subject) { this.subject = subject; this.subject.Attach(this); } public void SendNotify() { Console.WriteLine("Send Email!"); } } static void Main(string[] args) { Account account = new Account(); Email email = new Email(); Phone phone = new Phone(account); account.AmountChange(); return; }
说明:在这里,被调用方是否被调用的决定决在被调用方;
7.总结
总的看来,Observer与Command十分相似,都是将行为抽象,让行为独立的变化。只不过在调用方是否调用被调用方的决定权有所不同,在Command中决定决在调用方,在Observer中决定权在被调用方。在Observer中,如果被调用的方法已在某个类实现,也可以像Command命令模式那样再融合下适配器模式,加入一个Receiver类。