研磨设计模式day11观察者模式

目录

场景

代码示例

定义

观察者模式的优缺点

本质

何时选用

简单变型-区别对待观察者


场景

我是一家报社,每当我发布一个新的报纸时,所有订阅我家报社的读者都可以接收到

代码示例

报纸对象

package day11观察者模式;

import java.util.Observable;

/**
 * 报纸对象
 */
public class NewsPaper extends Observable {
    /**
     * 报纸的内容
     */
    private String content;

    /**
     * 获取报纸的具体内容
     * @return 报纸的具体内容
     */
    public String getContent() {
        return content;
    }

    /**
     * 示意,设置报纸的具体内容,相当于要出版报纸了
     * @param content 报纸的具体内容
     */
    public void setContent(String content) {
        this.content = content;
        // 内容有了,说明又出新报纸了,那就通知所有的读者
        this.setChanged();
        // 然后主动通知,用的推的方式
        this.notifyObservers(this.content);
        // 如果用拉的方式,这么调用
//        this.notifyObservers();
    }
}

读者,也就是观察者

package day11观察者模式;

import java.util.Observable;
import java.util.Observer;

/**
 * 真正的读者,也就是观察者
 */
public class Reader implements Observer {

    /**
     * 读者的姓名
     */
    private String name;

    public String getName() {
        return name;
    }

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

    @Override
    public void update(Observable o, Object arg) {
        // 这里采用推的方式
        System.out.println(name + "收到报纸了,进行阅读。目标推过来的内容是===" + arg);
        // 这里是获取拉的数据
//        System.out.println(name + "收到报纸了,进行阅读。主动到目标对象去拉的内容是===" + ((NewsPaper)o).getContent());
    }
}

client

package day11观察者模式;

/**
 * 客户端使用
 */
public class Client {
    public static void main(String[] args) {
        // 1.创建一个报纸,作为被观察者
        NewsPaper subject = new NewsPaper();
        // 2.创建阅读者,也就是观察者
        Reader reader1 = new Reader();
        reader1.setName("张三");

        Reader reader2 = new Reader();
        reader2.setName("李四");

        Reader reader3 = new Reader();
        reader3.setName("王五");

        // 3.注册阅读者
        subject.addObserver(reader1);
        subject.addObserver(reader2);
        subject.addObserver(reader3);

        // 4.要出报纸啦
        subject.setContent("本期内容是观察者模式");
    }
}

 解析:

报社就是一个发布者,读者就是一个个订阅者,发布者提供订阅方法,每次发布者发布新的东西时,就会通知订阅者这条新的消息。

报社NewsPaper:它继承了Observable类,这个类包含了注册方法,提示改变,通知方式(推和拉)等方法,NewsPaper包含了报纸内容对象,get方法就不说了,set时会进行提示改变了,并主动通知,用的推的方式。

观察者Reader:它实现了Observer接口,实现了update方法,java实现观察者模式时默认是拉模型,如果使用推模型,那么在update这个方法里通过推拉的获取方式都可以获取到值

定义

类似发布订阅模式

观察者模式的优缺点

本质

观察者模式的本质:触发联动

在程序运行期间,通过这样的联动可以控制观察者,在update执行的时候。

何时选用

简单变型-区别对待观察者

举例:根据水质污染的严重程度来分别告知不同的管理者

思路:将水质污染当作被观察的目标,监测员、预警人员和领导就是观察者。在目标里面进行判断,满足就通知,不满足不通知。

观察者接口

1.被通知的方法2.设置观察人员的职务3.获取观察人员的职务

package day11观察者模式.高级;

/**
 * 水质观察者接口定义
 */
public interface WatcherObserver {
    /**
     * 被通知的方法
     * @param subject 传入被观察的目标对象
     */
    public void update(WaterQualitySubject subject);

    /**
     * 设置观察人员的职务
     * @param job
     */
    public void setJob(String job);

    /**
     * 获取观察人员的职务
     * @return
     */
    public String getJob();
    
}

观察者的具体实现

package day11观察者模式.高级;

public class Watcher implements WatcherObserver{
    private String job;

    @Override
    public void update(WaterQualitySubject subject) {
        // 这里采用拉的方式
        System.out.println(job + "获取到通知,当前污染级别为: " + subject.getPolluteLevel());
    }

    @Override
    public void setJob(String job) {
        this.job = job;
    }

    @Override
    public String getJob() {
        return job;
    }
}

目标的父对象(抽象类) :1.定义抽象是因为我们不需要全部都发消息,所以让子类去根据业务的实际需要自己去选择性的通知。2.而且在我们传入目标对象的时候具有很好的封装性,不需要对外展示具体的目标对象,传给观察者的只是目标的父抽象类。

package day11观察者模式.高级;

import java.util.ArrayList;
import java.util.List;

/**
 * 定义目标的父对象
 */
public abstract class WaterQualitySubject {
    /**
     * 用来保存注册的观察者对象
     */
    protected List<WatcherObserver> observers = new ArrayList<WatcherObserver>();

    /**
     * 注册观察者对象
     * @param observer  观察者对象
     */
    public void attach(WatcherObserver observer){
        observers.add(observer);
    }

    /**
     * 删除观察者对象
     * @param observer
     */
    public void detach(WatcherObserver observer){
        observers.remove(observer);
    }

    /**
     * 通知对应的观察者对象
     */
    public abstract void notifyWatchers();

    /**
     * 获取水质污染的级别
     */
    public abstract int getPolluteLevel();
}

目标的实现(继承目标父抽象类)

package day11观察者模式.高级;

/**
 * 具体的检测对象
 */
public class WaterQuality extends WaterQualitySubject{
    /**
     * 污染的级别,0正常 1轻度污染 2中度污染 3高度污染
     */
    private int polluteLevel = 0;

    /**
     * 获取水质污染的级别
     * @return
     */
    @Override
    public int getPolluteLevel() {
        return polluteLevel;
    }

    /**
     * 当检测水质情况后,设置水质污染的级别
     * @param polluteLevel 水质污染的级别
     */
    public void setPolluteLevel(int polluteLevel) {
        this.polluteLevel = polluteLevel;
        // 通知相应的观察者
        this.notifyWatchers();
    }

    /**
     * 通知相应的观察者对象
     */
    @Override
    public void notifyWatchers() {
        // 循环所有注册的观察者
        for (WatcherObserver watcher : observers) {
            // 开始根据污染级别判断都通知谁
            if (this.polluteLevel >= 0 ){
                // 通知监测员做记录
                if ("监测人员".equals(watcher.getJob())){
                    watcher.update(this);
                }
            }
            if (this.polluteLevel >= 1 ){
                // 通知监测员做记录
                if ("预警人员".equals(watcher.getJob())){
                    watcher.update(this);
                }
            }
            if (this.polluteLevel >= 2 ){
                // 通知监测员做记录
                if ("领导".equals(watcher.getJob())){
                    watcher.update(this);
                }
            }
        }
    }


}

client

package day11观察者模式.高级;

public class Client {
    public static void main(String[] args) {
        // 创建具体的检测对象
        WaterQuality subject = new WaterQuality();

        // 创建几个观察者
        Watcher watcher1 = new Watcher();
        watcher1.setJob("监测人员");
        Watcher watcher2 = new Watcher();
        watcher2.setJob("预警人员");
        Watcher watcher3 = new Watcher();
        watcher3.setJob("领导");

        // 注册观察者
        subject.attach(watcher1);
        subject.attach(watcher2);
        subject.attach(watcher3);

        // 填写水质报告
        System.out.println("水质正常---");
        subject.setPolluteLevel(0);
        System.out.println("轻度污染---");
        subject.setPolluteLevel(1);
        System.out.println("重度污染---");
        subject.setPolluteLevel(2);
    }
}

解析:

从client开始,先创建了具体的检测对象, 他有什么用呢?可以注册观察者,可以发布通知

创建了几个观察者实现对象,给他们赋予了不同的职务。

将观察者跟目标对象进行关联,也就是注册,点进去看一下,调用了attach方法,这个方法不是具体的检测对象本身的,而是它的抽象父类中的方法

都注册进去之后,目标对象开始运行,他现在出了一个水质为0的污染报告,这个时候应该传递给谁信息呢?

 

点进这个setPolluteLevel(0)看一下 。这个是具体的检测对象本身的方法。

可以看出首先将传过来的值赋值给当前对象,然后调用了 this.notifyWatchers()方法。我们接着往下。

进来这个方法后,遍历所有注册到目标对象的观察者(订阅了该目标对象的订阅者),这个observers哪里来的?(),是注册而来的。

接着判断属于哪一类的污染,此时过来的污染为0,就判断当前观察者的职务是不是检测人员,如果是就调用update更新的方法,如果不是就不用管。

我们看一下update,被通知方法的接口

 接下来看看它的实现

 解析:判断是不是检测人员,如果是我就给他发送消息(它就能接收到消息)。

如果污染为1,那么就满足两个条件,就会给预警人员和检测人员都发送消息

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

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

相关文章

Ubuntu20.04配置mysql配置主从复制

ubuntu20.04&#xff1a;mysql主库 sudo vim /etc/mysql/mysql.conf.d/mysqld.cnf # 修改完毕重启 sudo service mysql stop sudo service mysql start主库mysqld.cnf配置 [mysqld] ... # bind-address>->--- 127.0.0.1 # 注释掉&#xff0c;允许外部连接 # mysqlx-b…

Spark整合hive的时候出错

Spark整合hive的时候 连接Hdfs不从我hive所在的机器上找&#xff0c;而是去连接我的集群里的另外两台机器 但是我的集群没有开 所以下面就一直在retry 猜测&#xff1a; 出现这个错误的原因可能与core-site.xml和hdfs-site.xml有关&#xff0c;因为这里面配置了集群的nameno…

浅析 GlusterFS 与 JuiceFS 的架构异同

在进行分布式文件存储解决方案的选型时&#xff0c;GlusterFS 无疑是一个不可忽视的考虑对象。作为一款开源的软件定义分布式存储解决方案&#xff0c;GlusterFS 能够在单个集群中支持高达 PiB 级别的数据存储。自从首次发布以来&#xff0c;已经有超过十年的发展历程。目前&am…

Pycharm通过SSH配置centos上Spark环境

直接在shell进行pyspark进行编程&#xff0c;程序没有办法写得太长&#xff0c;而且我们希望能够实现一个及时给出结果的编程环境&#xff0c;可以使用pycharm连接centos上的spark&#xff0c;进行本地编程&#xff0c;同步到centos系统中运行程序&#xff0c;并把结果返回pych…

IMS中Binder案例

IMS中Binder案例 1、FWK层中AIDL形式1.1 服务端实现Stub1.2 客户端获取proxy 2、Native层中AIDL形式2.1 服务端对应Bn端2.2 客户端对应Bp端 android12-release 1、FWK层中AIDL形式 Android 接口定义语言 (AIDL)、Android 应用层 到 HAL 层 AIDL形式是Android中binder机制的具体…

HAproxy服务及keepalived+haproxy高可用

本节主要学习AHproxy 的概述&#xff0c;安装&#xff0c;调度算法&#xff0c;配置文件&#xff0c;负载均衡&#xff0c;配置syslog日志&#xff0c;keepalivedhaproxy实现高可用。 目录 一、概述 1、简介 2、核心功能 3、关键特性 4、应用场景 二、安装 1.内核配置 …

Delphi 开发手持机(android)打印机通用开发流程(举一反三)

目录 一、场景说明 二、厂家应提供的SDK文件 三、操作步骤&#xff1a; 1. 导出Delphi需要且能使用的接口文件&#xff1a; 2. 创建FMX Delphi项目&#xff0c;将上一步生成的接口文件&#xff08;V510.Interfaces.pas&#xff09;引入: 3. 将jarsdk.jar 包加入到 libs中…

开始MySQL之路——MySQL安装和卸载

MySQL的介绍 MySQL数据库管理系统由瑞典的DataKonsultAB公司研发&#xff0c;该公司被Sun公司收购&#xff0c;现在Sun公司又被Oracle公司收购&#xff0c;因此MySQL目前属于Oracle旗下产品。 MySQL所使用的SQL语言是用于访问数据库的最常用标准化语言。MySQL软件采用了双授权…

四、Kafka Broker

4.1.1 Zookeeper 存储的 Kafka 信息 4.1.2 Kafka Broker 总体工作流程 4.2 生产经验 - 节点的服役和退役 自己的理解&#xff1a;其实就是将kafka的分区&#xff0c;负载到集群中的各个节点上。 1、服役新节点 2、退役旧节点 4.3 kafka副本 1、副本的作用 2、Leader的…

共享内存 windows和linux

服务端&#xff0c;即写入端 #include <iostream> #include <string.h> #define BUF_SIZE 1024 #ifdef _WIN32 #include <windows.h> #define SHARENAME L"shareMemory" HANDLE g_MapFIle; LPVOID g_baseBuffer; #else #define SHARENAME "sh…

Node.js 的 Buffer 是什么?一站式了解指南

在 Node.js 中&#xff0c;Buffer 是一种用于处理二进制数据的机制。它允许你在不经过 JavaScript 垃圾回收机制的情况下直接操作原始内存&#xff0c;从而更高效地处理数据&#xff0c;特别是在处理网络流、文件系统操作和其他与 I/O 相关的任务时。Buffer 是一个全局对象&…

Sql Server导出数据库到另一个数据库

1.打开sql server数据库&#xff0c;连接到服务器后&#xff0c;找到需要导出的数据库&#xff0c;右击后选择 任务->导出数据。 2.点击 下一步。 3.身份验证可以使用SQL Server身份验证&#xff0c;就是当时建立连接时的用户名和密码&#xff0c;数据库名称使用默认的&…

深度学习入门教学——二分分类

1、什么是二分分类&#xff1f; 二分分类就是判断“有”和“没有”、“是”和“不是”的问题&#xff0c;也就是监督学习中的分类问题。例如&#xff0c;输入一张图片&#xff0c;输出识别该图片的标签。计算机输入图片转化过程如下&#xff1a; 2、神经网络常用符号表示 (x, …

一次harbor升级导致镜像项目访问无权限问题

一、问题背景 将环境中现运行的harbor版本升级到2.6.2版本&#xff0c;相关同事升级完&#xff0c;发现有部分镜像项目点进去报无权限问题&#xff0c;镜像项目无法使用&#xff0c;但是也有部分项目是可以正常提供使用的。 二、问题处理过程 1、根据报错反馈没权限&#xff…

量化QAT QLoRA GPTQ

模型量化的思路可以分为PTQ&#xff08;Post-Training Quantization&#xff0c;训练后量化&#xff09;和QAT&#xff08;Quantization Aware Training&#xff0c;在量化过程中进行梯度反传更新权重&#xff0c;例如QLoRA&#xff09;&#xff0c;GPTQ是一种PTQ的思路。 QAT…

桥梁安全监测方法和内容是什么?

桥梁安全监测方法和内容是什么?桥梁监测是保障桥梁安全和稳定的重要手段。随着科技的进步&#xff0c;桥梁监测技术和设备不断完善&#xff0c;监测内容也越来越全面。本文万宾科技小编将为大家介绍桥梁安全监测的方法和内容&#xff0c;以期帮助大家更好地了解这一领域。 桥梁…

分布式计算框架:Spark、Dask、Ray

目录 什么是分布式计算 分布式计算哪家强&#xff1a;Spark、Dask、Ray 2 选择正确的框架 2.1 Spark 2.2 Dask 2.3 Ray 什么是分布式计算 分布式计算是一种计算方法&#xff0c;和集中式计算是相对的。 随着计算技术的发展&#xff0c;有些应用需要非常巨大的计算能力才…

Django(3)-创建第一个数据模型-ORM映射

数据库配置 根目录下settings.py 。这是个包含了 Django 项目设置的 Python 模块。 通常&#xff0c;这个配置文件使用 SQLite 作为默认数据库。如果你不熟悉数据库&#xff0c;或者只是想尝试下 Django&#xff0c;这是最简单的选择。Python 内置 SQLite&#xff0c;所以你无…

汽车电子笔记之:AUTOSA架构下的多核OS操作系统

目录 1、AUTOSAR多核操作系统 1.1、OS Application 1.2、多核OS的软件分区 1.3、任务调度 1.4、核间任务同步 1.5、计数器、报警器、调度表 1.6、自旋锁与共享资源 1.7、核间通信IOC 1.8、OS Object中元素交互 1.9、多核OS的启动与关闭 2、多核OS注意事项 2.1、最小…

使用Python批量将飞书文档转为MD

说明&#xff1a;飞书是在线文档平台&#xff0c;本文介绍如何使用Python程序批量将飞书文档转为MD文档&#xff0c;并下载到本地&#xff1b; 复制地址 首先&#xff0c;把文档的URL都复制下来&#xff0c;这个需要一个一个点&#xff0c;并复制拷贝&#xff0c;但却是工作量…