C#面向对象设计模式纵横谈 学习笔记19 Observer观察者模式(行为型模式)

本文介绍了一种设计模式——观察者模式,通过实例演示了如何利用该模式实现对象间的依赖关系,使得当一个对象状态发生变化时,所有依赖于它的对象都能得到通知并自动更新。文章还探讨了观察者模式在.NET事件机制中的应用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

 

意图
       定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时, 所有依赖于它的对象都得到通知并被自动更新。

动机
在软件构建过程中,我们需要为某些对象建立一种"通知依赖关系"。一个对象(目标对象)的状态发生改变,所有的依赖对象(观察者对象)都将得到通知。如果这样的依赖关系过于紧密,将使软件不能很好的抵御变化。
使用面向对象技术,可以将这种依赖关系弱化,并形成一种稳定的依赖关系。从而实现软件体系结构的松耦合。

我们先看看代码

  1. public class ATM
  2.     {
  3.         BankAccount bankAccount;
  4.         
  5.         public void Process(int data)
  6.         {
  7.             bankAccount.WithDraw(data); 
  8.         }
  9.     }
  10.     
  11.     public class BankAccount
  12.     {
  13.         Emailer emailer;
  14.         Mobile mobile;
  15.         public void WithDraw(int data)
  16.         {
  17.             emailer.SendEmail(userEmail);
  18.             mobile.SendNotification(telephone);
  19.         }
  20.     }
  21.     
  22.     public class Emailer
  23.     {
  24.         public void SendEmail(string to)
  25.         {
  26.             
  27.         }
  28.     }
  29.     
  30.     public class Mobile
  31.     {
  32.         public void SendNotification(string telephone)
  33.         {
  34.             
  35.         }
  36.     }

 

现在是这样一个场景有一个ATM自动柜员机,当账户信息发生改变的时候,我们要通过email和移动电话来发送消息。但是像上面这样写代码,会出现一个问题。假设我现在要增加一种通知方法,我需要添加一个类。然后在BankAccount里添加一个对象,并且在WithDraw方法里面调用新增对象的方法。很明显,现在是一种紧耦合的关系。

我们把代码改改

 

  1. public class ATM
  2.     {        
  3.         public void Process(int data)
  4.         {
  5.             bankAccount.WithDraw(data); 
  6.         }
  7.     }
  8.     
  9.     public abstract class Subject
  10.     {
  11.         List<IAccountObserver> observerList = new List<IAccountObserver>();
  12.         protected virtual void AddObserver(IAccountObserver observer)
  13.         {
  14.             observerList.Add(observer);
  15.         }
  16.         
  17.         protected virtual void RemoveObserver(IAccountObserver observer)
  18.         {
  19.             observerList.Remove(observer);
  20.         }
  21.         
  22.         protected virtual void Notify()
  23.         {
  24.             UserAccountArgs args = new UserAccountArgs();
  25.             
  26.             foreach(IAccountObserver observer in observerList)
  27.             {
  28.                 observer.Update(args);
  29.             }
  30.         }
  31.     }
  32.     
  33.     public class BankAccount : Subject
  34.     {
  35.         public void WithDraw(int data)
  36.         {
  37.             Notify();
  38.         }
  39.     }
  40.     public interface IAccountObserver
  41.     {
  42.         void Update(UserAccountArgs args);
  43.     }
  44.     
  45.     public class Mobile : IAccountObserver
  46.     {
  47.         #region IAccountObserver 成员
  48.         public void Update(UserAccountArgs args)
  49.         {
  50.             string mobileNumber = args.MobileNumber;
  51.         }
  52.         #endregion
  53.     }
  54.     
  55.     public class Emailer : IAccountObserver
  56.     {
  57.         public void SendEmail(string to)
  58.         {
  59.             
  60.         }
  61.         #region IAccountObserver 成员
  62.         public void Update(UserAccountArgs args)
  63.         {
  64.             string toAddress = args.ToAddress;
  65.         }
  66.         #endregion
  67.     }

我们抽象了一个接口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类抽象出来可以增加灵活度

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值