我的编程空间,编程开发者的网络收藏夹
学习永远不晚

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

短信预约 信息系统项目管理师 报名、考试、查分时间动态提醒
省份

北京

  • 北京
  • 上海
  • 天津
  • 重庆
  • 河北
  • 山东
  • 辽宁
  • 黑龙江
  • 吉林
  • 甘肃
  • 青海
  • 河南
  • 江苏
  • 湖北
  • 湖南
  • 江西
  • 浙江
  • 广东
  • 云南
  • 福建
  • 海南
  • 山西
  • 四川
  • 陕西
  • 贵州
  • 安徽
  • 广西
  • 内蒙
  • 西藏
  • 新疆
  • 宁夏
  • 兵团
手机号立即预约

请填写图片验证码后获取短信验证码

看不清楚,换张图片

免费获取短信验证码

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

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

讲故事(user story)

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

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

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

  2. 增加顾客的积分

  3. 开始按订单需求制券

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

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

需求分析

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

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

敲黑板.划重点

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

观察者模式结构图

Show Code

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

/// 
/// 抽象通知者
/// 
public abstract class Subject
{
    /// 
    /// 观察者集合
    /// 
    protected List observers = new List();

    public string State { get; set; }

    /// 
    /// 添加观察者
    /// 
    /// 观察者
    public void Attach(IObserver observer)
    {
        observers.Add(observer);
    }

    /// 
    /// 删除观察者
    /// 
    /// 观察者
    public void Detach(IObserver observer)
    {
        observers.Remove(observer);
    }

    /// 
    /// 通知
    /// 
    /// 
    public void Notify()
    {
        foreach (var observer in observers)
        {
            observer.Update();
        }
    }
}

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

 /// 
 /// 支持成功通知者
 /// 
 public class PaySuccessSubject : Subject
 {
 }

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

 /// 
 /// 抽象观察
 /// 
 public abstract class Observer
 {
     public abstract void Update();
 }

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

    /// 
    /// 短信观察者
    /// 
    public class MessageObserver : Observer
    {
        public Subject Subject { get; set; }

        public MessageObserver(Subject subject)
        {
            Subject = subject;
        }

        public override void Update()
        {
            Console.WriteLine($"{Subject.State}:短信通知了...");
        }
    }
    /// 
    /// 积分观察者
    /// 
    public class BonusObserver : Observer
    {
        public Subject Subject { get; set; }

        public BonusObserver(Subject subject)
        {
            Subject = subject;
        }

        public override void Update()
        {
            Console.WriteLine($"{Subject.State}:积分增加了...");
        }
    }

    /// 
    /// 券观察者
    /// 
    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("

Happy Ending~");
            Console.ReadLine();
        }

结果显示
result2

Code Upgrade

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

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

    /// 
    /// 抽象观察
    /// 
    public abstract class Observer
    {
        public abstract Task UpdateAsync();
    }

    /// 
    /// 短信观察者
    /// 
    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;
        }
    }

    /// 
    /// 积分观察者
    /// 
    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;
        }
    }

    /// 
    /// 券观察者
    /// 
    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}:制券完成...");
        }
    }

    /// 
    /// 抽象通知者
    /// 
    public abstract class Subject
    {
        /// 
        /// 观察者集合
        /// 
        protected List observers = new List();

        public string State { get; set; }

        /// 
        /// 添加观察者
        /// 
        /// 观察者
        public void Attach(Observer observer)
        {
            observers.Add(observer);
        }

        /// 
        /// 删除观察者
        /// 
        /// 观察者
        public void Detach(Observer observer)
        {
            observers.Remove(observer);
        }

        /// 
        /// 通知
        /// 
        /// 
        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("

Happy Ending~");
            Console.ReadLine();
        }

结果显示:

result

委托加持观察者模式

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

直接上代码:

    /// 
    /// 短信观察者
    /// 
    public class MessageObserver
    {
        public ISubject Subject { get; set; }

        public MessageObserver(ISubject subject)
        {
            Subject = subject;
        }

        /// 
        /// 发送短信
        /// 
        /// 
        public Task SendMessageAsync()
        {
            Console.WriteLine($"{Subject.State}:短信通知了...");
            return Task.CompletedTask;
        }
    }

    /// 
    /// 积分观察者
    /// 
    public class BonusObserver
    {
        public ISubject Subject { get; set; }

        public BonusObserver(ISubject subject)
        {
            Subject = subject;
        }

        /// 
        /// 添加积分
        /// 
        /// 
        public Task AddBonusAsync()
        {
            Console.WriteLine($"{Subject.State}:积分增加了...");
            return Task.CompletedTask;
        }
    }

    /// 
    /// 券观察者
    /// 
    public class CouponObserver
    {
        public ISubject Subject { get; set; }

        public CouponObserver(ISubject subject)
        {
            Subject = subject;
        }

        /// 
        /// 制券
        /// 
        /// 
        public async Task MakeCouponAsync()
        {
            Console.WriteLine($"{Subject.State}:开始制券...");
            //模拟制券耗时
            await Task.Delay(3000);
            Console.WriteLine($"{Subject.State}:制券完成...");
        }
    }

    /// 
    /// 抽象通知者
    /// 
    public interface ISubject
    {
        /// 
        /// 通知
        /// 
        /// 
        public Task Notify();

        public string State { get; set; }
    }

    /// 
    /// 支持成功通知者
    /// 
    public class PaySuccessSubject : ISubject
    {
        public Func 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("

Happy Ending~");
            Console.ReadLine();
        }
    }
}

展示结果和上面一样。

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

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

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

下载Word文档到电脑,方便收藏和打印~

下载Word文档

猜你喜欢

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

讲故事(user story)假设我们是一个优惠券提供平台,故事就发生在顾客在我们平台采购完成支付成功后。支付完成后平台要进行的一些操作:短信通知客户已经生成订单增加顾客的积分开始按订单需求制券​ 。。。(可能会有许多操作)接下来就是将故事以代码的形式展
设计模式-观察者模式(Observer)
2018-06-15

设计模式系列—观察者模式

本篇和大家一起来学习观察者模式相关内容。
观察者模式2024-12-14

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

观察者模式是一种行为设计模式, 允许你定义一种订阅机制, 可在对象事件发生时通知多个 “观察” 该对象的其他对象。

Java设计模式中的观察者模式

观察者模式定义对象之间的一种一对多的依赖关系,使得每当一个对象的状态发生变化时,其相关的依赖对象都可以得到通知并被自动更新。主要用于多个不同的对象对一个对象的某个方法会做出不同的反应
2023-02-16

一文搞懂设计模式—观察者模式

观察者模式在许多场景下都非常有用,但在使用时需要注意性能问题、循环依赖和执行顺序等方面的考虑。

PHP设计模式之观察者模式浅析

观察者模式是极其重要的一个设计模式,也是我几年开发过程中使用最多的设计模式,本文首先概述观察者模式的基本概念和Demo实现,接着是观察者模式在Java和Spring中的应用,最后是对观察者模式的应用场景和优缺点进行总结
2023-05-14

PHP设计模式中观察者模式详解

观察者模式是极其重要的一个设计模式,也是我几年开发过程中使用最多的设计模式,本文首先概述观察者模式的基本概念和Demo实现,接着是观察者模式在Java和Spring中的应用,最后是对观察者模式的应用场景和优缺点进行总结
2022-12-20

PHP设计模式中观察者模式讲解

本文实例讲述了PHP设计模式之观察者模式定义与用法。分享给大家供大家参考,观察者模式当一个对象的状态发生改变时,依赖他的对象会全部收到通知,并自动更新
2022-11-13

前端的设计模式系列-观察者模式

大部分讲设计模式的文章都是使用的 Java、C++ 这样的以类为基础的静态类型语言,作为前端开发者,js 这门基于原型的动态语言,函数成为了一等公民,在实现一些设计模式上稍显不同,甚至简单到不像使用了设计模式,有时候也会产生些困惑。

编程热搜

目录