本文作者:小黑黑

[设计模式]行为型模式之观察者模式

小黑黑 1年前 ( 2019-03-05 ) 284 抢沙发
[设计模式]行为型模式之观察者模式摘要: 一、引言        今天学习的是【行为型】设计模式中的观察者模式,看到“观察者”者三个字,大家应...

一、引言

        今天学习的是【行为型】设计模式中的观察者模式,看到“观察者”者三个字,大家应该想到的是既然有观察者,那一定会有一个被观察者,当被观察者的某些的某些行为或动作被改变时,观察者对象能够收到相应的信息。在现实生活中也有很多观察者模式的例子,比如:我们都用QQ,我们就相当于一个观察者,QQ群就相当于一个被观察者,当有人在群里面发送消息时,我们都能够接收到消息,相关的例子还有银行系统,当你去存钱或取钱时,银行都会给你发送短息提醒你账户余额有所变动。

二、动机

        建立一种对象与对象之间的依赖关系,一个对象发生改变时将自动通知其他对象, 其他对象将相应做出反应。再次,发生改变的对象称之为观察目标,而被通知的对象成为观察者,一个观察者目标可以对应多个观察者,而且这些观察者之间没有相互联系,可以根据需要增加或删除观察者,使得系统更易于扩展,这就是观察者模式的动机

三、意图

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

四、结构图

123.PNG

4.1  模式的组成

        1、抽象主题角色(Subject):把所有观察者对象的引用都保存在一个列表中,并提供增加和删除观察者对象的操作。

        2、具体主题角色(ConcreteSubject):实现抽象主题接口。

        3、抽象观察者角色(Observer):为所有观察者对象定义一个接口,在得到主题通知时做出相应的动作。

        4、具体观察者角色(ConcreteObserver):实现抽象观察者角色所要求的接口。

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

        下面我们将以银行系统举例,当储户的账户余额发生改变时,银行通知用户账户信息:

    /// <summary>
    /// 银行短信系统抽象类,相当于抽象主题角色Subject,被观察者 
    /// </summary>
    public abstract class BaseBankMessageSystem
    {
        public List<BaseDepositor> _depositoryList = new List<BaseDepositor>();

        /// <summary>
        /// 增加储户
        /// </summary>
        public abstract void Add(BaseDepositor depositor);

        /// <summary>
        /// 删除储户
        /// </summary>
        public abstract void Delete(BaseDepositor depositor);

        /// <summary>
        /// 储户账户金额变化时短信通知储户
        /// </summary>
        public virtual void Notify()
        {
            foreach (var depositor in _depositoryList)
            {
                if (depositor.Change)
                {
                    depositor.Update(depositor.Money, depositor.OpTime);
                    depositor.Change = false;
                }
            }
        }
    }
    
    /// <summary>
    /// 交通银行短信系统,相当于具体主题角色ConcreteSubject
    /// </summary>
    public class JiaoTongBankMessageSystem : BaseBankMessageSystem
    {

        /// <summary>
        /// 增加储户
        /// </summary>
        /// <param name="depositor"></param>
        public override void Add(BaseDepositor depositor)
        {
            //如果系统中不存在该储户,则添加
            if (!this._depositoryList.Contains(depositor))
            {
                this._depositoryList.Add(depositor);
            }
        }

        /// <summary>
        /// 删除储户
        /// </summary>
        /// <param name="depositor"></param>
        public override void Delete(BaseDepositor depositor)
        {
            //如果系统中存在该储户,则删除
            if (this._depositoryList.Contains(depositor))
            {
                this._depositoryList.Remove(depositor);
            }
        }
    }
    
    /// <summary>
    /// 储户的抽象类,相当于抽象观察者角色,ObServer
    /// </summary>
    public abstract class BaseDepositor
    {
        public string Name { get; set; }

        public decimal Money { get; set; }

        public bool Change { get; set; } = false;

        public DateTime OpTime { get; set; }

        public BaseDepositor(string name, decimal money)
        {
            this.Name = name;
            this.Money = money;
        }

        /// <summary>
        /// 取钱
        /// </summary>
        /// <param name="money">金额</param>
        public void WithdrawMoney(decimal money)
        {
            if (money <= this.Money && money > 0M)
            {
                this.Money = this.Money - money;
                this.Change = true;
                this.OpTime = DateTime.Now;
            }
        }

        /// <summary>
        /// 更新储户信息
        /// </summary>
        public abstract void Update(decimal currentMoney, DateTime dateTime);
    }
    
    /// <summary>
    /// 具体储户,相当于具体观察者角色,ConcreteObserver
    /// </summary>
    public class Depositors : BaseDepositor
    {
        public Depositors(string name, decimal money) : base(name, money)
        {
        }

        public override void Update(decimal currentMoney, DateTime dateTime)
        {
            Console.WriteLine($"尊敬的 {this.Name},您的账户发生了变化,当前余额:{currentMoney}, 余额变动时间:{dateTime}");
        }
    }
    
    class Program
    {
        static void Main(string[] args)
        {

            //创建两位储户
            BaseDepositor zhangSan = new Depositors("张三", 1000);
            BaseDepositor liSi = new Depositors("李四", 5000);

            BaseBankMessageSystem jiaoTongBank = new JiaoTongBankMessageSystem();
            jiaoTongBank.Add(zhangSan);
            jiaoTongBank.Add(liSi);

            //张三取500块钱
            zhangSan.WithdrawMoney(500);
            jiaoTongBank.Notify();

            //李四取钱
            liSi.WithdrawMoney(1000);
            jiaoTongBank.Notify();

            Console.Read();
        }
    }

5.1  观察者模式分析

        1、观察者模式描述了如何建立对象与对象之间的依赖关系,如何构造满足这种需求的系统。

        2、这一模式中的关键对象是观察目标和观察者,一个目标可以有任意数目的与之想依赖的观察者,一旦目标的状态发生改变,所有的观察者都将得到通知。

        3、作为对这个通知的响应,每个观察者都将即时更新自己的状态,以与目标状态同步,这种交互也称为发布 - 订阅。目标是通知的发布者,它发出通知时并不需要知道谁是它的观察者,可以有任意数目的观察者订阅它并接收通知。

六、观察者模式的优缺点

优点:

        1、观察者模式可以表现表示层和数据逻辑层的分离,并定义了稳定的消息更新传递机制,抽象了更新接口,使得可以有各种各样不同的表示层作为具体观察者角色。

        2、观察者模式在观察目标和观察者之间建立一个抽象的耦合。

        3、观察者模式支持广播通信。

        4、观察者模式符合“开闭原则”。

缺点:

        1、如果一个观察目标有很多直接和间接的观察者的话,将所有的观察者都通知到会花费很多时间。

        2、如果观察者和观察目标之间有循环依赖的话,观察目标出触发它们之间进行循环调用,可能导致系统崩溃。

        3、观察者没有相应的机制让观察者知道所观察的目标对象是怎样发生变化的,而仅仅只是知道观察目标发生了变化。

分享到: 网站分享代码

发表评论

快捷回复:

评论列表 (暂无评论,284人围观)参与讨论

还没有评论,来说两句吧...