定义

定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并被自动更新。

观察者模式的UML类图及说明

如上图(图片来源于《head_first设计模式》)所示,观察者的uml中主要有以下类

1.主题Subject(接口)

Subject 对象带有绑定观察者到 Client 对象和从 Client 对象解绑观察者的方法,主要为观察者注册方法(registerObserver),观察者删除方法(removeObserver),通知观察者方法(notifyObservers)

2.观察者Observer(接口)

Observer观察者一般是一个接口,每一个实现该接口的实现类都是具体观察者。主要提供一个update方法。

3.具体主题ConcreteSubject(Subject的具体实现)

是对主题Subject接口的具体实现,该类可根据具体业务扩展

4.具体观察者ConcreteObserver(Observer的具体实现)

是对Observer观察者的具体实现,一般订阅者会有多个,所以该类可通过自己需要的消息进行扩展

观察者模式的优缺点及应用场景

优点:

1.观察者和被观察者是抽象耦合的。

2.建立一套触发机制。

缺点:

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

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

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

应用场景:

1.关联行为场景

2.事件多级触发场景

4.跨系统的消息变换场景,如消息队列的处理机制

应用实例:

1.新闻的发布订阅

2.天气信息的发布订阅

注意事项:

1、JAVA 中已经有了对观察者模式的支持类。

2、避免循环引用。

3、如果顺序执行,某一观察者错误会导致系统卡壳,一般采用异步方式。

Spring中的观察者模式

1.事件(ApplicationEvent)

ApplicationEvent 是所有事件对象的父类。ApplicationEvent 继承自 jdk 的 EventObject, 所有的事件都需要继承 ApplicationEvent, 并且通过source得到事件源。

2.事件监听(ApplicationListener)

ApplicationListener 事件监听器,也就是观察者。继承自 jdk 的 EventListener,该类中只有一个方法 onApplicationEvent。当监听的事件发生后该方法会被执行。

3.事件发布(ApplicationContext)

ApplicationContext 是 Spring 中的核心容器,在事件监听中 ApplicationContext 可以作为事件的发布者,也就是事件源。因为 ApplicationContext 继承自 ApplicationEventPublisher。在 ApplicationEventPublisher 中定义了事件发布的方法 — publishEvent(Object event)

4.事件管理(ApplicationEventMulticaster)

ApplicationEventMulticaster 用于事件监听器的注册和事件的广播。监听器的注册就是通过它来实现的,它的作用是把 Applicationcontext 发布的 Event 广播给它的监听器列表。

观察者模式的实现

现在的线上直播模式非常的火,在这里,以简单的LOL比赛信息订阅为例。比如我们要关注今天有哪些了LPL的比赛信息,后几天有哪些比赛信息,我们就可以点击订阅,订阅后,有新的比赛信息,就会推送给你。

这样的场景下,我们就可以用观察者模式来实现:

定义主题接口

/** * 主题接口,对象通过此接口注册为观察者,或者把自己从观察者中删除 * * @author yyl */public interface Subject {    /**     * 观察者注册     *     */    void registerObserver(Observer observer);    /**     * 删除观察者     *     */    void removeObserver(Observer observer);    /**     * 通知观察者     *     */    void notifyObservers();}

定义主题接口的具体实现,及LOL比赛信息主题

/** * lol主题 * * @author yyl */public class LolSubject implements Subject {    /** 今日比赛信息*/    private String msg;    /** 后几日比赛信息*/    private List msgList;    // 用户列表    private static List userList = new ArrayList<>();    @Override    public void registerObserver(Observer observer) {        userList.add(observer);    }    @Override    public void removeObserver(Observer observer) {        userList.remove(observer);    }    @Override    public void notifyObservers() {        userList.forEach(observer -> observer.update());    }    /**     * 发布信息,并通知观察者     *     * @author yyl     */    public void setMsgs(String msg,List msgList){        // 更改通知信息        this.msg = msg;        this.msgList = msgList;        // 通知观察者        notifyObservers();    }    public String getMsg() {        return msg;    }    public List getMsgList() {        return msgList;    }}

定义观察者Observer

/** * 观察者Observer,观察者一般是一个接口,每一个实现该接口的实现类都是具体观察者 * * @author yyl */public interface Observer {    /**     * 接受消息后的具体逻辑处理     */    void update();}

具体观察者,今日比赛信息观察者

/** * 具体观察者,今日比赛信息观察者 * * @author yyl */public class CurrentObserver implements Observer {    /**lol比赛信息主题 */    private LolSubject subject;    /**订阅的信息 */    private String msg;    public CurrentObserver(LolSubject subject) {        this.subject = subject;        // 观察者注册        this.subject.registerObserver(this);    }    @Override    public void update() {        this.msg = this.subject.getMsg();        System.out.println("今日比赛:" + this.msg);    }}

具体观察者,后几日比赛信息观察者

/** * 具体观察者,后几日比赛信息观察者 * * @author yyl */public class FutureObserver implements Observer {    /**lol比赛信息主题 */    private LolSubject subject;    /**订阅的信息 */    private List msgList;    public FutureObserver(LolSubject subject) {        this.subject = subject;        // 观察者注册        this.subject.registerObserver(this);    }    @Override    public void update() {        this.msgList = this.subject.getMsgList();        System.out.println("比赛预告:");        msgList.forEach(s -> System.out.println(s));    }}

通知者进行通知 Client

public class TestObserver {    public static void main(String[] args) {        // 主题        LolSubject lolSubject = new LolSubject();        // 观察者        CurrentObserver currentObserver = new CurrentObserver(lolSubject);        FutureObserver futureObserver = new FutureObserver(lolSubject);        List msgList = new ArrayList<>();        msgList.add("2020-06-22 RNG VS IG");        msgList.add("2020-06-22 VG VS LGD");        msgList.add("2020-06-22 V5 VS OMG");        // 发布信息        lolSubject.setMsgs("TSE VS FPX", msgList);    }}

如上代码,有两个观察者,在发布信息的比赛信息后,观察者就可以获取自己关注的信息,然后进行自己的业务逻辑处理。代码输出如下

有Java相关问题可以私聊作者

head first设计模式 pdf_设计模式之观察者模式相关推荐

  1. Javascript乱弹设计模式系列(1) - 观察者模式(Observer)

    前言 博客园谈设计模式的文章很多,我也受益匪浅,包括TerryLee.吕震宇等等的.NET设计模式系列文章,强烈推荐.对于我,擅长于前台代码的开发,对于设计模式也有一定的了解,于是我想结合Javasc ...

  2. C#设计模式之十六观察者模式(Observer Pattern)【行为型】

    C#设计模式之十六观察者模式(Observer Pattern)[行为型] 原文:C#设计模式之十六观察者模式(Observer Pattern)[行为型] 一.引言 今天是2017年11月份的最后一 ...

  3. 行为型设计模式(4)—— 观察者模式(Observer Pattern)

    文章目录 1.概述 2.实例 2.1 丑陋的设计 2.2 使用观察者模式 3.应用场景 4.优缺点 5.小结 参考文献 1.概述 使用设计模式可以提高代码的可复用性.可扩充性和可维护性.观察者模式(O ...

  4. php设计模式课程---4、观察者模式的好处是什么

    php设计模式课程---4.观察者模式的好处是什么 一.总结 一句话总结: 方便选择之后去控制监听的板块数:比如选择男士之后,我可以决定监听广告里面的第二和第三板块. 1.为什么有观察者模式? 错误理 ...

  5. 设计模式混编:观察者模式+中介者模式

    针对变化万千的业务需求,采用合适的设计模式是可以轻松应对的. 本文将探索多种优秀设计模式的混编来解决复杂场景的问题,实现1+1>2的效果.应用实践离不开基础,所以文章将以基本概念.设计初衷出发, ...

  6. Unity游戏设计模式(二)观察者模式(Observer Pattern)

    最近看游戏设计模式,当看到观察者模式时被搞得云里雾里的,什么观察者,被观察者,抽象观察者,抽象被观察者.听着这些词就觉得可怕,其实理解以后还是比较简单的. 当我们玩游戏时,经常会出现一些事件,而这个事 ...

  7. 设计模式(35)-----设计模式阶段性总结(一句话概括一个模式)

    假如你现在还在为自己的技术担忧,假如你现在想提升自己的工资,假如你想在职场上获得更多的话语权,假如你想顺利的度过35岁这个魔咒,假如你想体验BAT的工作环境,那么现在请我们一起开启提升技术之旅吧,详情 ...

  8. 深入浅出设计模式之设计模式简介

    一.什么是设计模式(详见设计模式概念和七大原则) 在GoF(Gang of Four)的书籍<Design Patterns - Elements of Reusable Object-Orie ...

  9. 行为设计模式 - 观察者设计模式

    行为设计模式 - 观察者设计模式 观察者模式是行为设计模式之一.当您对对象的状态感兴趣并希望在有任何更改时收到通知时,观察者设计模式非常有用.在观察者模式中,监视另一个对象状态的对象称为Observe ...

最新文章

  1. np.max()和np.argmax()
  2. 为什么python画不了图-python-为什么pygame不画一个圆?
  3. 霍金一生重要时刻照片合集,3次来中国,年轻时也是帅哥一枚
  4. Mac 系统引导过程概述 BootCamp 的秘密
  5. linux交叉编译无法识别gcc编译器
  6. 使用Spring boot,Thymeleaf,AngularJS从零开始构建新的Web应用程序-第2部分
  7. java 线程 spring_java中spring里实现多线程
  8. mac find桌面显示desktop问题
  9. 利用openpyxl来读取Excel数据
  10. Xcode中的iOS工程模板
  11. 手动连接mysql_手动实现与数据库的连接
  12. 通过本地上传工具把CSV文件导入到百会报表
  13. 怎么制作html静态页面,如何做静态网页
  14. OpenRefine中的正则表达式
  15. 数字图像处理编程入门
  16. 微信默认表情符号的代码对照表
  17. bzoj3168-钙铁锌硒维生素
  18. 【学习记录】阿里天池SQL练习题1-python与SQL方式比较
  19. 手机、浏览器的分辨率、状态栏参数
  20. 服务器2016自动备份怎么取消,wps中ppt的制作怎样取消掉定时自动备份

热门文章

  1. Firebug方便分解网页的小工具
  2. 充电枪cp信号控制板_筋膜枪究竟是不是智商税?评测后,我的回答更坚定了
  3. JavaSE----异常处理
  4. matlab 复数求模长,matlab计算带有复数的函数,最后求复数函数的模,结果里面却有...
  5. python sys模块详解_python之sys模块详解
  6. websocket连接出现 HTTP Authentication failed; no valid credentials available
  7. MariaDB设置root用户密码
  8. Android开发笔记(三十七)按钮类控件
  9. 显著性检测(saliency detection)评价指标之KL散度距离Matlab代码实现
  10. linux任务计划详解