本笔记摘抄自:https://www.cnblogs.com/PatrickLiu/p/7928521.html,记录一下学习过程以备后续查用。

    一、引言

    今天我们要讲行为型设计模式的第四个模式--观察者模式,先从名字上来看。观察者模式可以理解为既然有“观察者”,那肯定就有“被观察者”了。“观察者”监视着“被观察者”,如果“被观察者”有所行动,“观察者”就会做出相应的动作来回应。听起来是不是有点像“谍战”的味道?比如“谍影重重”那类优秀的影片。

    观察者模式在现实生活中,实例其实是很多的,比如:八九十年代我们订阅的报纸,我们会定期收到报纸,因为我们订阅了。银行可以给储户发手机短信,也是观察者模式很好的使用的例子,因为我们订阅了银行的短信业务,当我们账户余额发生变化就会收到通知。还有很多,我就不一一列举了,发挥大家的想象吧。好了,接下来,就让我们看看该模式具体是怎么实现的吧。

    二、观察者模式介绍

    观察者模式:英文名称--Observer Pattern;分类--行为型。

    2.1、动机(Motivate)

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

    2.2、意图(Intent)

    定义对象间的一种一对多的依赖关系,以便当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并自动更新。——《设计模式》GoF

    2.3、结构图

C#设计模式学习笔记:(16)观察者模式

    2.4、模式的组成

    可以看出,在观察者模式的结构图有以下角色:

    1)抽象主题角色(Subject):抽象主题把所有观察者对象的引用保存在一个列表中,并提供增加和删除观察者对象的操作,抽象主题角色又叫做抽象被观察者角色,一般由抽象类或接口实现。

    2)抽象观察者角色(Observer):为所有具体观察者定义一个接口,在得到主题通知时更新自己,一般由抽象类或接口实现。

    3)具体主题角色(ConcreteSubject):实现抽象主题接口,具体主题角色又叫做具体被观察者角色。

    4)具体观察者角色(ConcreteObserver):实现抽象观察者角色所要求的接口,以便使自身状态与主题的状态相协调。

    2.5、观察者模式的具体实现

    观察者模式在显示生活中也有类似的例子,比如:我们订阅银行短信业务,当我们账户发生改变,我们就会收到相应的短信。类似的还有微信订阅号,今天我们以订阅银行短信业务为例来讲讲观察者模式的实现,实现代码如下:

C#设计模式学习笔记:(16)观察者模式
    class Program
    {
        /// <summary>
        /// 银行短信系统抽象接口,是被观察者--该类型相当于抽象主题角色Subject。
        /// </summary>
        public abstract class BankMessageSystem
        {
            protected IList<Depositor> observers;

            //构造函数初始化观察者列表实例
            protected BankMessageSystem()
            {
                observers = new List<Depositor>();
            }

            //增加预约储户
            public abstract void Add(Depositor depositor);

            //删除预约储户
            public abstract void Delete(Depositor depositor);

            //通知储户
            public void Notify()
            {
                foreach (Depositor depositor in observers)
                {
                    if (depositor.AccountIsChanged)
                    {
                        depositor.Update(depositor.Balance, depositor.OperationDateTime);
                        //账户发生变化并且通知后,则可认为账户已无变化。
                        depositor.AccountIsChanged = false;
                    }
                }
            }
        }

        /// <summary>
        /// 广东银行短信系统,是被观察者--该类型相当于具体主题角色ConcreteSubject。
        /// </summary>
        public sealed class GuangDongBankMessageSystem : BankMessageSystem
        {
            //增加预约储户
            public override void Add(Depositor depositor)
            {
                //应该先判断该用户是否已预约?如未预约则增加到列表中,这里简化了。
                observers.Add(depositor);
            }

            //删除预约储户
            public override void Delete(Depositor depositor)
            {
                //应该先判断该用户是否有预约?如有则删除,否则不操作,这里简化了。
                observers.Remove(depositor);
            }
        }

        /// <summary>
        /// 储户的抽象接口--相当于抽象观察者角色(Observer)
        /// </summary>
        public abstract class Depositor
        {
            //储户的名称,假设是唯一的。
            public string Name { get; private set; }

            //储户的余额
            public int Balance { get; private set; }

            //账户操作时间
            public DateTime OperationDateTime { get; set; }

            //账户是否发生变化
            public bool AccountIsChanged { get; set; }

            //初始化状态数据
            protected Depositor(string name, int total)
            {
                Name = name;
                Balance = total;            //存款总额等于余额
                AccountIsChanged = false;   //账户未发生变化
            }

            //取钱
            public void GetMoney(int num)
            {
                if (num <= Balance && num > 0)
                {
                    Balance -= num;
                    AccountIsChanged = true;
                    OperationDateTime = DateTime.Now;
                }
            }

            //更新储户状态
            public abstract void Update(int currentBalance, DateTime dateTime);
        }

        /// <summary>
        /// 广东的具体储户--相当于具体观察者角色ConcreteObserver
        /// </summary>
        public sealed class GuangDongDepositor : Depositor
        {
            public GuangDongDepositor(string name, int total) : base(name, total) { }

            public override void Update(int currentBalance, DateTime dateTime)
            {
                Console.WriteLine(string.Format(Name + ",您的账户余额有变化,发生时间:{0},当前余额:{1}元。", dateTime.ToString(), currentBalance.ToString()));
            }
        }

        static void Main(string[] args)
        {
            #region 观察者模式
            //假设有3位储户,都是武林高手,也比较有钱。
            Depositor huangFeiHong = new GuangDongDepositor("黄飞鸿", 3000);
            Depositor fangShiYu = new GuangDongDepositor("方世玉", 1300);
            Depositor hongXiGuan = new GuangDongDepositor("洪熙官", 2500);
            BankMessageSystem guangDongBank = new GuangDongBankMessageSystem();

            //这三位开始订阅银行短信业务
            guangDongBank.Add(huangFeiHong);
            guangDongBank.Add(fangShiYu);
            guangDongBank.Add(hongXiGuan);

            //早上黄飞鸿取了100块钱
            huangFeiHong.GetMoney(100);
            guangDongBank.Notify();

            //中午黄飞鸿和方世玉各取了200块
            huangFeiHong.GetMoney(200);
            fangShiYu.GetMoney(200);
            guangDongBank.Notify();

            //晚上他们三个都取了钱
            huangFeiHong.GetMoney(300);
            fangShiYu.GetMoney(300);
            hongXiGuan.GetMoney(300);
            guangDongBank.Notify();

            Console.Read();
            #endregion
        }
    }
View Code

相关文章:

  • 2021-09-30
  • 2022-01-13
  • 2021-06-30
  • 2022-12-23
  • 2022-12-23
  • 2021-06-08
  • 2022-12-23
猜你喜欢
  • 2021-08-05
  • 2021-08-07
  • 2021-09-17
  • 2021-06-30
  • 2022-01-18
相关资源
相似解决方案