3分钟看懂设计模式02:观察者模式

一、什么是观察者模式

观察者模式又叫做发布-订阅模式或者源-监视器模式

结合它的各种别名大概就可以明白这种模式是做什么的。

其实就是观察与被观察,一个对象(被观察者)的状态改变会被通知到观察者,并根据通知产生各自的不同的行为。

以下为《设计模式的艺术》中给出的定义:

观察者模式(Observer Pattern):定义对象之间的一种一对多依赖关系,使得每当一个对象状态发生改变时,其相关依赖对象皆得到通知并被自动更新

二、观察者模式的4个角色

Subject(目标)

Subject是被观察的对象。

Subject可以是接口、抽象类或者具体类。

它一般有4个要素

• 一个观察者集合,一般用Vector。

• 增加观察者的方法。

• 删除观察者的方法。

• 通知方法notify()。

ConcreteSubject(具体目标)

是Subject的子类,没什么特殊的,如果有抽象方法需要实现就实现,没有的话这个类不写也行。

Observer(观察者)

一般是个接口,声明一个update()方法。

ConcreteObserver(具体观察者)

刚开始学的话先会最简单的形式就可以了,就直接实现Observer接口,实现update()方法就完了。

三、观察者模式2个代码实现案例

通过2个案例,基本就可以知道观察者模式是怎么回事了,对照观察者模式的4个角色,敲一遍。

单纯熟悉4个角色的案例

先写一个被观察者Subject

public abstract class Subject {
    // 存放观察者的集合
    private Vector<Observer> obs = new Vector<>();

    public void addObserver(Observer obs) {
        this.obs.add(obs);
    }
    public void delObserver(Observer obs) {
        this.obs.remove(obs);
    }

    // 通知方法,写成抽象方法让ConcreteSubject实现也一样的
    protected void notifyObserver() {
        for (Observer ob : obs) {
            ob.update();
        }
    }
    // 这里也是可写可不写,根据业务需求
    public abstract void doSomething();

}

再写一个ConcreteSubject

public class ConcreteSubject extends Subject {
    @Override
    public void doSomething() {
        System.out.println("被观察者事件发生改变");
        this.notifyObserver();
    }
}

观察者接口Observer

public interface Observer {
    public void update();
}

观察者实现类ConcreteObserver,我们这里给出2个观察者

public class ConcreteObserver01 implements Observer {
    @Override
    public void update() {
        System.out.println("观察者01收到状态变化信息,并进行处理...");
    }
}
public class ConcreteObserver02 implements Observer {
    @Override
    public void update() {
        System.out.println("观察者02收到状态变化信息,并进行处理...");
    }
}

最后给出一个测试类,测试运行一个看看效果,看不明白代码就debug一下捋一捋。

以下代码的意思就是:

你得有东西被观察被监视吧?

所以先创建一个被观察者,比如我的账户余额。

你得设置哪些对象在观察、监视我的账户吧?

那就添加2个,我和我老婆。

然后就坐等账户余额有变化。

一旦发工资,状态变化!!!

图片

dosomething()!

notifyObserver()!

遍历观察者列表!

update()!

这个时候我和我老婆分别对应各自实现的update()方法。

我马上去买了游戏。

我老婆马上去买了化妆品。

(不过这个例子好像不太合适,因为update方法里又会导致账户余额的变化,循环起来了,不过大概明白咋回事就行了。)

    public class Client {
        public static void main(String[] args) {
            ConcreteSubject subject = new ConcreteSubject();
            subject.addObserver(new ConcreteObserver01());
            subject.addObserver(new ConcreteObserver02());
            subject.doSomething();
        }
    }

盟友受攻击发通知,其他盟友做出响应

这个例子也是《设计模式的艺术》给出的案例。

我们的需求如下:

联盟成员收到攻击→发送通知给盟友→盟友做出响应。

如果按照上述思路设计,则每个成员必须持有其他所有成员的状态信息,导致系统开销过大。所以我们引入一个战队控制中心来统一维护所有战队成员信息。

图片

依然是我们四步走:

先创建一个Subject被观察者,这里是AllyControlCenter控制中心

    public abstract class AllyControlCenter {

        /**
         * 战队名称
         */
        protected String allyName;
        /**
         * 定义一个集合,用来存储具体观察者,也就是战队成员
         */
        protected Vector<Observer> players = new Vector<Observer>();

        /**
         * 加入战队
         */
        public void join(Observer observer) {
            System.out.println(observer.getName() + "加入" + this.allyName + "战队!");
            players.add(observer);
        }

        /**
         * 退出战队
         */
        public void quit(Observer observer) {
            System.out.println(observer.getName() + "退出" + this.allyName + "战队!");
            players.remove(observer);
        }

        /**
         * 声明抽象通知方法
         * @param name
         */
        public abstract void notifyObserver(String name);

        /**
         * 设置成员变量方法
         * @param allyName
         */
        public void setAllyName(String allyName) {
            this.allyName = allyName;
        }

        /**
         * 获取成员变量方法
         * @return
         */
        public String getAllyName() {
            return this.allyName;
        }
    }

再创建一个ConcreteSubject具体被观察者ConcreteAllyControlCenter

    public class ConcreteAllayControlCenter extends AllyControlCenter {
        public ConcreteAllayControlCenter(String name) {
            System.out.println(name + "战队组建成功!");
            System.out.println("-------------");
            this.allyName = name;
        }

        /**
         * 实现通知方法
         * @param name
         */
        @Override
        public void notifyObserver(String name) {
            System.out.println(this.allyName + "战队紧急通知,盟友" + name + "遭受敌人攻击");
            // 遍历观察者集合,调用每一个盟友(除了自己)的支援方法
            for (Observer obs : players) {
                if (!obs.getName().equalsIgnoreCase(name)) {
                    obs.help();
                }
            }
        }
    }

创建一个抽象观察者Observer

    public interface Observer {
        public String getName();

        public void setName(String name);

        /**
         * 声明支援盟友的方法
         */
        public void help();

        /**
         * 声明遭受攻击的方法
         */
        public void beAttacked(AllyControlCenter acc);
    }

在创建具体观察者Player

public class Player implements Observer {
    private String name;

    public Player(String name) {
        this.name = name;
    }
    @Override
    public String getName() {
        return this.name;
    }

    @Override
    public void setName(String name) {
        this.name = name;
    }

    /**
     * 支援盟友的方法实现
     */
    @Override
    public void help() {
        System.out.println("坚持住,"+this.name +"来救你了!");
    }

    /**
     * 遭受攻击的方法实现
     * 当遭受攻击时,调用战队控制中心类的通知方法notifyObserver()来通知盟友
     * @param acc
     */
    @Override
    public void beAttacked(AllyControlCenter acc) {
        System.out.println(this.name + "被攻击!");
        acc.notifyObserver(name);
    }
}

测试运行

public class Client {
    public static void main(String[] args) {
        // 定义被观察者
        AllyControlCenter acc = new ConcreteAllayControlCenter("金庸群侠");

        // 定义4个观察者
        Observer player1 = new Player("杨过");
        Observer player2 = new Player("令狐冲");
        Observer player3 = new Player("张无忌");
        Observer player4 = new Player("段誉");
        acc.join(player1);
        acc.join(player2);
        acc.join(player3);
        acc.join(player4);

        // 某成员遭受攻击
        player1.beAttacked(acc);

    }
}

四、我什么时候用观察者模式?

  1. 1. 事件处理系统:例如,用户界面框架中,当用户进行某些操作(如点击按钮、移动鼠标等)时,可以使用观察者模式来通知相关的处理程序。

  2. 2. 数据订阅与发布系统:在需要向多个客户端发布数据更新的场景中,例如股票行情显示、新闻更新等,可以使用观察者模式。

  3. 3. 跨系统的消息交换:例如,在微服务架构中,服务间的事件可以通过观察者模式进行通信,确保各服务间的解耦。

  4. 4. 状态监控和警报系统:在需要监控某些状态并在特定条件下发送警报的系统中,观察者模式可以用来实现监控对象和警报系统之间的通信。

  5. 5. 配置管理:当系统配置信息发生变更时,使用观察者模式可以实时通知各个使用配置的组件进行相应的调整。


往期推荐:

● 师爷,翻译翻译什么叫AOP

● 翻译,师爷师爷什么叫事务

● 纪念JDBC

● SpringBoot实现动态数据源配置‍

● 聚簇索引、回表与覆盖索引

● Java锁到底是个什么东西

图片

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/405380.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

在Win11上部署Stable Diffusion WebUI Forge

Stable Diffusion WebUI Forge 是 Stable Diffusion WebUI&#xff08;基于 Gradio&#xff09;之上的平台&#xff0c;可简化开发、优化资源管理并加快推理速度。“Forge”这个名字的灵感来自“Minecraft Forge”。这个项目旨在成为SD WebUI的Forge。 与原始 WebUI&#xff0…

【LeetCode每日一题】 单调栈的案例84 柱状图中最大的矩形

84 柱状图中最大的矩形 给定 n 个非负整数&#xff0c;用来表示柱状图中各个柱子的高度。每个柱子彼此相邻&#xff0c;且宽度为 1 。 求在该柱状图中&#xff0c;能够勾勒出来的矩形的最大面积。 示例 1: 输入&#xff1a;heights [2,1,5,6,2,3] 输出&#xff1a;10 解释…

js 文件预览 在窗口设置“自定义名称”

1. 最近需要做一个点击表格某一列的标题&#xff0c;预览当前文件的一个小功能。本身功能很简单&#xff0c;点击该标题&#xff0c;预览文件&#xff0c;那么拿到他对应的文件地址&#xff0c;在浏览器打开就行了。 2. 事实如此&#xff0c;使用window.open(url, _blank);就行…

挑战杯 基于大数据的时间序列股价预测分析与可视化 - lstm

文章目录 1 前言2 时间序列的由来2.1 四种模型的名称&#xff1a; 3 数据预览4 理论公式4.1 协方差4.2 相关系数4.3 scikit-learn计算相关性 5 金融数据的时序分析5.1 数据概况5.2 序列变化情况计算 最后 1 前言 &#x1f525; 优质竞赛项目系列&#xff0c;今天要分享的是 &…

Java Swing游戏开发学习3

世界和摄像机World and Camera 这一节实现的是超过屏幕尺寸的世界地图&#xff0c;这里的世界不是我们的地球&#xff0c;指的是游戏中的虚拟世界。 这里的游戏示例是一个action RPG&#xff0c;即动作角色扮演游戏(action role play game)&#xff0c;因此地图尺寸超过了屏幕…

精通Django模板(模板语法、继承、融合与Jinja2语法的应用指南)

模板&#xff1a; 基础知识&#xff1a; ​ 在Django框架中&#xff0c;模板是可以帮助开发者快速⽣成呈现给⽤户⻚⾯的⼯具模板的设计⽅式实现了我们MVT中VT的解耦(M: Model, V:View, T:Template)&#xff0c;VT有着N:M的关系&#xff0c;⼀个V可以调⽤任意T&#xff0c;⼀个…

【Spring】 AOP面向切面编程

文章目录 AOP是什么&#xff1f;一、AOP术语名词介绍二、Spring AOP框架介绍和关系梳理三、Spring AOP基于注解方式实现和细节3.1 Spring AOP底层技术组成3.2 初步实现3.3 获取通知细节信息3.4 切点表达式语法3.5 重用&#xff08;提取&#xff09;切点表达式3.6 环绕通知3.7 切…

MongoDB从入门到实战之.NET Core使用MongoDB开发ToDoList系统(8)-Ant Design Blazor前端框架搭建

前言 前面的章节我们介绍了一些值得推荐的Blazor UI组件库&#xff0c;通过该篇文章的组件库介绍最终我选用Ant Design Blazor这个UI框架作为ToDoList系统的前端框架。因为在之前的工作中有使用过Ant Design Vue、Ant Design Angular习惯并且喜欢Ant Design设计规范和风格&…

集成TinyMCE富文本编辑器

若依的基础上集成TinyMCE富文本编辑器 前端bootstrap TinyMCE官网链接 TinyMCE所需静态资源下载链接 开源项目-若依链接 将TinyMCE静态资源包放入项目中&#xff1b; 代码引入css&#xff1a; <!-- 引入TinyMCE CSS --><link th:href"{/ajax/libs/tinymce/j…

XTuner InternLM-Chat 个人小助手认知微调实践

要解决的问题&#xff1a; 如何让模型知道自己做什么&#xff0c;是什么样身份。是谁创建了他&#xff01;&#xff01;&#xff01; 概述 目标&#xff1a;通过微调&#xff0c;帮助模型认清了解对自己身份弟位 方式&#xff1a;使用XTuner进行微调 微调前&#xff08;回答…

大数据 - Spark系列《十》- rdd缓存详解

Spark系列文章&#xff1a; 大数据 - Spark系列《一》- 从Hadoop到Spark&#xff1a;大数据计算引擎的演进-CSDN博客 大数据 - Spark系列《二》- 关于Spark在Idea中的一些常用配置-CSDN博客 大数据 - Spark系列《三》- 加载各种数据源创建RDD-CSDN博客 大数据 - Spark系列《…

Java基于微信小程序的智能停车场管理系统

博主介绍&#xff1a;✌程序员徐师兄、7年大厂程序员经历。全网粉丝12w、csdn博客专家、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和毕业项目实战✌ &#x1f345;文末获取源码联系&#x1f345; &#x1f447;&#x1f3fb; 精彩专栏推荐订阅&#x1f447;…

【计算机网络】数据链路层|封装成帧|透明传输|差错检测|PPP协议|CSMA/CD协议

目录 一、思维导图 ​ 二、数据链路层功能概述 1.数据链路层概述 2.数据链路层功能概述——封装成帧 3.数据链路层功能概述——透明传输 4.数据链路层功能概述——差错检测 三、数据链路层重要协议 1.数据链路层重要协议&#xff1a;PPP协议 2.数据链路层重要协议&#x…

成功解决TypeError: can‘t multiply sequence by non-int of type ‘float‘

&#x1f525; 成功解决TypeError: can’t multiply sequence by non-int of type ‘float’ &#x1f4c5; 日期&#xff1a;2024年2月23日 &#x1f308; 个人主页&#xff1a;高斯小哥 &#x1f525; 高质量专栏&#xff1a;Matplotlib之旅&#xff1a;零基础精通数据可视化…

MIT-BEVFusion系列九--CUDA-BEVFusion部署4 c++解析pytorch导出的tensor数据

目录 创建流打印 engine 信息打印结果内部流程 启动计时功能加载变换矩阵并更新数据&#xff08;重要&#xff09;内部实现 该系列文章与qwe一同创作&#xff0c;喜欢的话不妨点个赞。 在create_core方法结束后&#xff0c;我们的视角回到了main.cpp中。继续来看接下来的流程。…

蜂窝物联网咖WiFi认证解决方案

项目背景 随着目前网咖模式越来越流行&#xff0c;给网吧部署一套无缝漫游的WIFI网络势在必行。同时&#xff0c;网吧无线准入的验证码在客户机上面进行更新&#xff0c;以防周边的人员进行蹭网&#xff0c;损失网吧的外网带宽。 01 需求分析 1. 网吧服务区域全部覆盖无盲区…

harbor(docker仓库)仓库部署 - 高可用

harbor&#xff08;docker仓库&#xff09;仓库部署 - 高可用 1. harbor高可用1.1 方案说明1. 双主复制2. 多harbor实例共享后端存储 1.2 部署高可用&#xff08;多harbor实例共享后端存储&#xff09;1. 服务器划分2. 安装harbor&#xff08;先部署一套Harbor&#xff0c;用于…

Set集合(Java) 及底层原理

SET<E>是一个接口&#xff0c;添加的元素是无序的&#xff1a;添加数据的顺序和获取出的数据顺序不一致&#xff1b;不重复&#xff0c;无索引。 实现类&#xff1a; 1.HashSet&#xff1a;无序不重复无索引 2.LinkedHashSet&#xff1a;有序不重复无索引 3.TreeSet&…

聊天敏感词监控该怎样实现?

当员工在日常工作中&#xff0c;经常使用企业微信、钉钉等聊天通讯软件进行沟通和管理&#xff0c;不可避免地会出现员工和客户之间敏感行为的出现。 例如员工飞单、辱骂客户、私自承诺、收取红包等违规行为&#xff0c;这些不仅会影响公司形象&#xff0c;还会造成经济损失。…

企业级大数据安全架构(十一)Kerberos接入dophinscheduler

作者&#xff1a;楼高 建议将dophinscheduler集成到Ambari安装部署&#xff0c;在Ambari上面开启kerberos 1.安装准备 编译 从GitHub获取dolphinscheduler-1.3.9源码 git clone https://github.com/apache/dolphinscheduler.git -b 1.3.9-releasehttps://github.com/apache/…