欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

设计模式-观察者模式(Observer)

程序员文章站 2022-05-01 20:47:20
讲故事(user story) 假设我们是一个优惠券提供平台,故事就发生在顾客在我们平台采购完成支付成功后。 支付完成后平台要进行的一些操作: 1. 短信通知客户已经生成订单 2. 增加顾客的积分 3. 开始按订单需求制券 ​ 。。。(可能会有许多操作) 接下来就是将故事以代码的形式展现出来。。。 ......

讲故事(user story)

假设我们是一个优惠券提供平台,故事就发生在顾客在我们平台采购完成支付成功后。

支付完成后平台要进行的一些操作:

  1. 短信通知客户已经生成订单

  2. 增加顾客的积分

  3. 开始按订单需求制券

​ 。。。(可能会有许多操作)

接下来就是将故事以代码的形式展现出来。。。

需求分析

我们将上述故事转化为代码中的对象分别是: 支付成功 paysuccesssubject、短信通知 messageobserver、积分增加 bonusobserver、制券 couponobserver

当支付成功paysuccesssubject后,要通知到messageobserverbonusobservercouponobserver这三个对象,为了实现上面这个需求,将采用观察者模式(发布-订阅)

敲黑板.划重点

观察者模式又叫发布-订阅(publish/subscribe)模式,定义了一种一对多的依赖关系,让多个观察者对象同时 监听某一个主题对象。当主题对象在状态发生变化时,通知所有观察者对象,使他们能够自己更新自己。

设计模式-观察者模式(Observer)

show code

subject类,把所有观察者对象的引用保存在一个集合了,每个通知者都可以有任何数量的观察者。抽象通知者提供 可以增加和删除观察者对象的接口。

/// <summary>
/// 抽象通知者
/// </summary>
public abstract class subject
{
    /// <summary>
    /// 观察者集合
    /// </summary>
    protected list<iobserver> observers = new list<iobserver>();

    public string state { get; set; }

    /// <summary>
    /// 添加观察者
    /// </summary>
    /// <param name="observer">观察者</param>
    public void attach(iobserver observer)
    {
        observers.add(observer);
    }

    /// <summary>
    /// 删除观察者
    /// </summary>
    /// <param name="observer">观察者</param>
    public void detach(iobserver observer)
    {
        observers.remove(observer);
    }

    /// <summary>
    /// 通知
    /// </summary>
    /// <returns></returns>
    public void notify()
    {
        foreach (var observer in observers)
        {
            observer.update();
        }
    }
}

paysuccesssubject类,具体的通知者,给所有登记过的观察者发出通知。

 /// <summary>
 /// 支持成功通知者
 /// </summary>
 public class paysuccesssubject : subject
 {
 }

observer类,抽象观察者,为所有的具体的观察者定义一个接口,一般用抽象类或接口实现。通常包含一个update()更新方法。

 /// <summary>
 /// 抽象观察
 /// </summary>
 public abstract class observer
 {
     public abstract void update();
 }

messageobserverbonusobservercouponobserver具体的观察者类,实现更新接口,以便本身的状态与主题的状态相协调。

    /// <summary>
    /// 短信观察者
    /// </summary>
    public class messageobserver : observer
    {
        public subject subject { get; set; }

        public messageobserver(subject subject)
        {
            subject = subject;
        }

        public override void update()
        {
            console.writeline($"{subject.state}:短信通知了...");
        }
    }
    /// <summary>
    /// 积分观察者
    /// </summary>
    public class bonusobserver : observer
    {
        public subject subject { get; set; }

        public bonusobserver(subject subject)
        {
            subject = subject;
        }

        public override void update()
        {
            console.writeline($"{subject.state}:积分增加了...");
        }
    }

    /// <summary>
    /// 券观察者
    /// </summary>
    public class couponobserver : observer
    {
        public subject subject { get; set; }

        public couponobserver(subject subject)
        {
            subject = subject;
        }
        public override void update()
        {
            console.writeline($"{subject.state}:开始制券了...");
        }
    }

客户端代码

        private static void main(string[] args)
        {
            var subject = new paysuccesssubject();
            var observer1 = new couponobserver(subject);
            var observer2 = new messageobserver(subject);
            var observer3 = new bonusobserver(subject);

            //添加订阅
            subject.attach(observer1);
            subject.attach(observer2);
            subject.attach(observer3);

            //发布通知
            subject.state = "星巴克10十元券采购成功";
            subject.notify();

            console.writeline("\n\nhappy ending~");
            console.readline();
        }

结果显示
设计模式-观察者模式(Observer)

code upgrade

code review后发现,在通知给观察者时,是顺序执行,如果其中一个观察者卡顿或者错误,会导致其他观察者卡克,所以我们应该采用异步方式。

下面我们将模拟 制券过程耗时增加,但不影响通知其他观察者。直接上代码:

    /// <summary>
    /// 抽象观察
    /// </summary>
    public abstract class observer
    {
        public abstract task updateasync();
    }

    /// <summary>
    /// 短信观察者
    /// </summary>
    public class messageobserver : observer
    {
        public subject subject { get; set; }

        public messageobserver(subject subject)
        {
            subject = subject;
        }

        public override task updateasync()
        {
            console.writeline($"{subject.state}:短信通知了...");
            return task.completedtask;
        }
    }

    /// <summary>
    /// 积分观察者
    /// </summary>
    public class bonusobserver : observer
    {
        public subject subject { get; set; }

        public bonusobserver(subject subject)
        {
            subject = subject;
        }

        public override task updateasync()
        {
            console.writeline($"{subject.state}:积分增加了...");
            return task.completedtask;
        }
    }

    /// <summary>
    /// 券观察者
    /// </summary>
    public class couponobserver : observer
    {
        public subject subject { get; set; }

        public couponobserver(subject subject)
        {
            subject = subject;
        }

        public override async task updateasync()
        {
            console.writeline($"{subject.state}:开始制券...");
            //模拟制券耗时
            await task.delay(3000);
            console.writeline($"{subject.state}:制券完成...");
        }
    }

    /// <summary>
    /// 抽象通知者
    /// </summary>
    public abstract class subject
    {
        /// <summary>
        /// 观察者集合
        /// </summary>
        protected list<observer> observers = new list<observer>();

        public string state { get; set; }

        /// <summary>
        /// 添加观察者
        /// </summary>
        /// <param name="observer">观察者</param>
        public void attach(observer observer)
        {
            observers.add(observer);
        }

        /// <summary>
        /// 删除观察者
        /// </summary>
        /// <param name="observer">观察者</param>
        public void detach(observer observer)
        {
            observers.remove(observer);
        }

        /// <summary>
        /// 通知
        /// </summary>
        /// <returns></returns>
        public task notify()
        {
            foreach (var observer in observers)
            {
                observer.updateasync();
            }
            return task.completedtask;
        }
    }

客户端端代码:

        private static async task main(string[] args)
        {
            var subject = new paysuccesssubject();
            var observer1 = new couponobserver(subject);
            var observer2 = new messageobserver(subject);
            var observer3 = new bonusobserver(subject);

            //添加订阅
            subject.attach(observer1);
            subject.attach(observer2);
            subject.attach(observer3);

            //发布通知
            subject.state = "星巴克10十元券采购成功";
            await subject.notify();

            console.writeline("\n\nhappy ending~");
            console.readline();
        }

结果显示:

设计模式-观察者模式(Observer)

委托加持观察者模式

现实开发中,很多观察者对象共同继承或者实现同一个抽象观察者,不合适;并且所有观察者对象的操作方法统一叫一个 update(),达不到望文生义的效果,所以我们对观察者模式再次进行升级,使用委托来替换掉抽象观察者,

直接上代码:

    /// <summary>
    /// 短信观察者
    /// </summary>
    public class messageobserver
    {
        public isubject subject { get; set; }

        public messageobserver(isubject subject)
        {
            subject = subject;
        }

        /// <summary>
        /// 发送短信
        /// </summary>
        /// <returns></returns>
        public task sendmessageasync()
        {
            console.writeline($"{subject.state}:短信通知了...");
            return task.completedtask;
        }
    }

    /// <summary>
    /// 积分观察者
    /// </summary>
    public class bonusobserver
    {
        public isubject subject { get; set; }

        public bonusobserver(isubject subject)
        {
            subject = subject;
        }

        /// <summary>
        /// 添加积分
        /// </summary>
        /// <returns></returns>
        public task addbonusasync()
        {
            console.writeline($"{subject.state}:积分增加了...");
            return task.completedtask;
        }
    }

    /// <summary>
    /// 券观察者
    /// </summary>
    public class couponobserver
    {
        public isubject subject { get; set; }

        public couponobserver(isubject subject)
        {
            subject = subject;
        }

        /// <summary>
        /// 制券
        /// </summary>
        /// <returns></returns>
        public async task makecouponasync()
        {
            console.writeline($"{subject.state}:开始制券...");
            //模拟制券耗时
            await task.delay(3000);
            console.writeline($"{subject.state}:制券完成...");
        }
    }

    /// <summary>
    /// 抽象通知者
    /// </summary>
    public interface isubject
    {
        /// <summary>
        /// 通知
        /// </summary>
        /// <returns></returns>
        public task notify();

        public string state { get; set; }
    }

    /// <summary>
    /// 支持成功通知者
    /// </summary>
    public class paysuccesssubject : isubject
    {
        public func<task> update;

        public string state { get; set; }

        public task notify()
        {
            update();
            return task.completedtask;
        }
    }
}

客户端调用:

    internal class program
    {
        private static async task main(string[] args)
        {
            var subject = new observerdelegate.paysuccesssubject();
            var observer1 = new observerdelegate.couponobserver(subject);
            var observer2 = new observerdelegate.messageobserver(subject);
            var observer3 = new observerdelegate.bonusobserver(subject);
            //添加订阅
            subject.update += observer1.makecouponasync;
            subject.update += observer2.sendmessageasync;
            subject.update += observer3.addbonusasync;
            //发布通知
            subject.state = "星巴克10十元券采购成功";
            await subject.notify();

            console.writeline("\n\nhappy ending~");
            console.readline();
        }
    }
}

展示结果和上面一样。

源码地址:https://gitee.com/sayook/designmode