意图
定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时, 所有依赖于它的对象都得到通知并被自动更新。
动机
在软件构建过程中,我们需要为某些对象建立一种"通知依赖关系"。一个对象(目标对象)的状态发生改变,所有的依赖对象(观察者对象)都将得到通知。如果这样的依赖关系过于紧密,将使软件不能很好的抵御变化。
使用面向对象技术,可以将这种依赖关系弱化,并形成一种稳定的依赖关系。从而实现软件体系结构的松耦合。
我们先看看代码
- public class ATM
- {
- BankAccount bankAccount;
- public void Process(int data)
- {
- bankAccount.WithDraw(data);
- }
- }
- public class BankAccount
- {
- Emailer emailer;
- Mobile mobile;
- public void WithDraw(int data)
- {
- emailer.SendEmail(userEmail);
- mobile.SendNotification(telephone);
- }
- }
- public class Emailer
- {
- public void SendEmail(string to)
- {
- }
- }
- public class Mobile
- {
- public void SendNotification(string telephone)
- {
- }
- }
现在是这样一个场景有一个ATM自动柜员机,当账户信息发生改变的时候,我们要通过email和移动电话来发送消息。但是像上面这样写代码,会出现一个问题。假设我现在要增加一种通知方法,我需要添加一个类。然后在BankAccount里添加一个对象,并且在WithDraw方法里面调用新增对象的方法。很明显,现在是一种紧耦合的关系。
我们把代码改改
- public class ATM
- {
- public void Process(int data)
- {
- bankAccount.WithDraw(data);
- }
- }
- public abstract class Subject
- {
- List<IAccountObserver> observerList = new List<IAccountObserver>();
- protected virtual void AddObserver(IAccountObserver observer)
- {
- observerList.Add(observer);
- }
- protected virtual void RemoveObserver(IAccountObserver observer)
- {
- observerList.Remove(observer);
- }
- protected virtual void Notify()
- {
- UserAccountArgs args = new UserAccountArgs();
- foreach(IAccountObserver observer in observerList)
- {
- observer.Update(args);
- }
- }
- }
- public class BankAccount : Subject
- {
- public void WithDraw(int data)
- {
- Notify();
- }
- }
- public interface IAccountObserver
- {
- void Update(UserAccountArgs args);
- }
- public class Mobile : IAccountObserver
- {
- #region IAccountObserver 成员
- public void Update(UserAccountArgs args)
- {
- string mobileNumber = args.MobileNumber;
- }
- #endregion
- }
- public class Emailer : IAccountObserver
- {
- public void SendEmail(string to)
- {
- }
- #region IAccountObserver 成员
- public void Update(UserAccountArgs args)
- {
- string toAddress = args.ToAddress;
- }
- #endregion
- }
我们抽象了一个接口IAccountObserver,Emailer类和Mobile类都实现了这个接口。在Subject抽象类中,我们定义了一个IAccountObserver的List集合,并且通过AddObserver和RemoveObserver方法来添加或减少观察者对象,在Notify方法里面,我们遍历这个List集合,调用IAccountObserver结构规定的Update方法。BankAccount类继承了Subject抽象类,在WithDraw方法里调用了Notify方法。这里可能会有疑问,为什么要将Subject类抽象出来,而不直接使用BankAccount类?这里当然是有原因的,我们可以重写Notify方法,因为,并不是所有的方法调用都需要将所有的观察者都通知到的,我们将Subject类抽象出来可以增加灵活度。在Command模式中我也说明来在Java中实现事件的机制,后一个例子就是java的事件机制,java宏只不过将addObsever改成了addListener.
大家看了上面的代码觉得有点类似.net中的事件机制了。实际上事件就是一种观察者模式。
我们看看事件的申明
public event delegate EventName
那么delegate实际上就是潜在的一个接口,他规定了观察者函数的返回值及参数(delegate)规定的。并且我们也可以为这个事件添加多个观察者(多个事件处理器)。我们在Command模式里面了解到委托delegate是command模式的变种,那么我们可以知道事件是observer模式的变种
要点
我们抽象了一个接口IAccountObserver,Emailer类和Mobile类都实现了这个接口。在Subject抽象类中,我们定义了一个IAccountObserver的List集合,并且通过AddObserver和RemoveObserver方法来添加或减少观察者对象,在Notify方法里面,我们遍历这个List集合,调用IAccountObserver结构规定的Update方法。BankAccount类继承了Subject抽象类,在WithDraw方法里调用了Notify方法。这里可能会有疑问,为什么要将Subject类抽象出来,而不直接使用BankAccount类?这里当然是有原因的,我们可以重写Notify方法,因为,并不是所有的方法调用都需要将所有的观察者都通知到的,我们将Subject类抽象出来可以增加灵活度