C#设计模式系列之观察者模式

473 阅读2分钟

观察者模式

定义对象一对多的依赖关系,当一个对象状态改变时,其它依赖它的对象状态也发生改变。


适用场景:

  • 一个抽象模型有两个方面,一个方面依赖另一个方面。将二者封装在两个独立的对象中,使它们能够独立使用和复用
  • 当一个对象状态改变,需要改变其它对象,可以是多个
  • 当一个对象需要通知其它对象,而不确定其它对象是谁,有多少个

例子

  1. 银行取钱,账户余额发生改变,然后短信通知、邮件通知、app通知……
  2. 热水器烧水,水开了,警示灯亮、提示音响、温度显示……

代码实现

以银行取钱为例

    /// <summary>
    /// 观察者接口
    /// </summary>
    public interface IObserverAccount
    {
        void Update(string text);
    }

账户对象

    /// <summary>
    /// 观察对象
    /// </summary>
    public  class SubjcetAccount
    {
        private List<IObserverAccount> observers = new List<IObserverAccount>();

        public string Name => "公子小白";

        private double _money = 10000.00;

        /// <summary>
        /// 剩余金额
        /// </summary>
        public double Money
        {
            get => _money;
            set => value = this._money;
        }

        /// <summary>
        /// 取出金额
        /// </summary>
        public double DelMoney { get; set; }

        /// <summary>
        /// 通知
        /// </summary>
        public void SendMsg(string text)
        {
            if (observers != null)
            {
                foreach (var item in observers)
                {
                    item.Update(text);
                }
            }
        }

        /// <summary>
        /// 取钱
        /// </summary>
        /// <param name="money"></param>
        public bool Withdraw(double money)
        {
            if (Money < money)
            {
                return false;
            }
            _money -= money;
            return true;
        }

        /// <summary>
        /// 订阅观察者
        /// </summary>
        /// <param name="account"></param>
        public void AddOberver(IObserverAccount account)
        {
            if (!observers.Exists(c => c.Equals(account)))
            {
                observers.Add(account);
            }
        }

        /// <summary>
        /// 移除观察者
        /// </summary>
        /// <param name="account"></param>
        public void RemoveOberver(IObserverAccount account)
        {
            if (observers.Exists(c => c.Equals(account)))
            {
                observers.Remove(account);
            }
        }
    }

邮件通知

    /// <summary>
    /// 邮件通知-观察者
    /// </summary>
    public class Email : IObserverAccount
    {
        public void Update(string text) => Console.WriteLine($"邮件通知:{text}");

    }

短信通知

    /// <summary>
    /// 手机通知-观察者
    /// </summary>
    public class Mobile : IObserverAccount
    {
        public void Update(string text) => Console.WriteLine($"短信通知:{text}");
    }

客户端调用

 var account = new SubjcetAccount();
 account.AddOberver(new Email());
 account.AddOberver(new Mobile());
 account.DelMoney = 1000.00;
 account.Withdraw(account.DelMoney);
 account.SendMsg($"{account.Name},你的账户支出{account.DelMony},余额为{account.Money}");

调用结果如下:

到这里一个观察者模式基本实现,其思想就是==发布-订阅==模式,观察对象是个发布者,观察者就是订阅者,它自行决定是否订阅发布者的通知。C#中有着强大丰富的事件和委托,那么接下来使用委托、事件来实现观察者模式(发布-订阅)。


观察者模式-委托事件版

定义一个委托

public delegate void NotifyEventHandler(object sender,string text);

定义一个账户(发布者),定义一个委托事件

    public class SubjectAccount
    {
        public event NotifyEventHandler NotifyEvent;

        public string Name => "公子小白";

        private double _money = 10000.00;

        /// <summary>
        /// 剩余金额
        /// </summary>
        public double Money
        {
            get => _money;
            set => value = this._money;
        }

        /// <summary>
        /// 取出金额
        /// </summary>
        public double DelMoney { get; set; }

        /// <summary>
        /// 取钱
        /// </summary>
        /// <param name="money"></param>
        public bool Withdraw(double money)
        {
            if (Money < money)
            {
                return false;
            }
            _money -= money;
            return true;
        }

        public  void OnNotifyChange()
        {
          if (NotifyEvent != null)
          {
              NotifyEvent(this,$"{Name},取出金额 {DelMoney},账户余额 {Money}");
          }
        }
    }

定义邮件通知(订阅者)

    /// <summary>
    /// 邮件通知-观察者
    /// </summary>
    public class EmailSubject 
    {
        public void Update(object obj,string text)
        {
            if (obj is SubjectAccount)
            {
                Console.WriteLine($"邮件通知:{text}");
            }
          
        }
    }

定义短信通知(订阅者)

    /// <summary>
    /// 手机通知-观察者
    /// </summary>
    public class MobileSubject 
    {
        public void Update(object obj,string text)
        {
            if (obj is SubjectAccount)
            {
                Console.WriteLine($"短信通知:{text}");
            }
        }
    }

客户端调用

            var account = new SubjectAccount();
            var email = new EmailSubject();
            var mobile = new MobileSubject();
            // 这里是不是很熟悉,就是winform开发中的事件添加方式
            account.NotifyEvent += mobile.Update;
            account.NotifyEvent += email.Update;
            account.DelMoney = 1000;
            account.Withdraw(account.DelMoney);
            account.OnNotifyChange();

调用结果如下:

本文使用 mdnice 排版