03-JAVA设计模式-观察者模式

观察者模式

什么是观察者模式

Java中的观察者模式是一种常见的设计模式,它允许对象(观察者)订阅另一个对象(被观察者)的状态变化,并在状态变化时自动得到通知。

核心:
观察者模式主要用于1:N的通知。当一个对象(目标对象)的状态发生变化时,它需要及时告知一系列对象(观察者对象)令他们做出响应。

通知观察者的方式:

  • 推:
    • 每次都会把通知以广播的方式发送给所有观察者,所有观察者只能被动接收。
  • 拉:
    • 观察者只要知道有情况即可。至于什么时候获取内容,获取什么内容都可以自主决定。

优点:

  • 解耦:观察者模式降低了对象之间的耦合度,使得它们可以独立地改变和复用。
  • 扩展性:新的观察者可以很容易地加入到现有系统中,而无需修改其他部分的代码。
  • 灵活性:观察者模式允许在运行时动态地改变观察者和被观察者的关系。

缺点:

  • 开发和调试复杂:由于系统中存在多个观察者和被观察者,开发和调试可能会变得相对复杂。
  • 性能问题:如果观察者数量庞大,或者被观察者状态改变频繁,可能会导致性能下降。
  • 消息通知顺序:在Java中,消息的通知一般是顺序执行的,一个观察者卡顿可能会影响整体的执行效率。

常见场景:

  • 图形用户界面(GUI)开发:在GUI应用程序中,当用户与界面进行交互(例如点击按钮或拖动滑块)时,界面的某些部分可能需要更新以反映这些变化。观察者模式允许这些部分(观察者)自动响应这些事件,而无需手动调用更新方法。
  • 游戏开发:在游戏中,玩家和NPC的行为,如移动、攻击、受伤等,都可能触发一系列事件。观察者模式可以用来注册和通知这些事件的监听器,以便游戏逻辑能够实时响应并更新游戏状态。
  • 消息传递系统:在分布式系统或微服务架构中,组件之间需要传递消息以实现通信和协作。观察者模式允许一个组件(被观察者)在产生消息时通知所有订阅了该消息的组件(观察者),从而实现高效的消息传递。
  • 实时数据监控:在需要实时跟踪和响应数据变化的场景中,如股票价格监控、传感器数据读取等,观察者模式可以帮助实现当数据变化时自动触发相应的处理逻辑。
  • 状态管理:当应用程序中某个对象的状态发生变化,并且需要通知其他对象进行相应的处理时,可以使用观察者模式。例如,一个订单状态的改变可能需要通知库存系统、支付系统等多个系统进行相应的操作。

案例1

推方式实现,以广播方式发送消息所有观察者

UML

在这里插入图片描述

实现步骤:

  • 创建观察者接口,定义通过被观察者更新状态接口
  • 创建被观察者,被观察者持有所有观察者的引用,提供注册、移除、通知所有观察者的方法,定义状态属性,提供get/set方法set方法中默认通知所有观察者

实现代码

Observer.java

// 观察者接口
public interface Observer {
    void update(Subject subject);
}

Subject.java

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

// 被观察者
public class Subject {
    // 定义存储观察者的集合
    private List<Observer> observerList = new ArrayList<Observer>();
    // 定义状态属性
    private String state;

    // 注册观察者
    public void registerObserver(Observer observer){
        observerList.add(observer);
    }

    // 移除观察者
    public void removeObserver(Observer observer){
        observerList.remove(observer);
    }

    // 通知所有观察者
    public void notifyObservers(){
        for(Observer observer : observerList){
            observer.update(this);
        }
    }

    public String getState() {
        return state;
    }

    public void setState(String state) {
        this.state = state;
        notifyObservers();
    }
}

ObserverA.java

// 观察者A
public class ObserverA implements Observer{
    @Override
    public void update(Subject subject) {
        System.out.printf("观察者A接收到消息-state:%s%n",subject.getState());
    }
}

ObserverB.java

// 观察者B
public class ObserverB implements Observer{
    @Override
    public void update(Subject subject) {
        System.out.printf("观察者B接收到消息-state:%s%n",subject.getState());
    }
}

TestClient.java

public class TestClient {
    public static void main(String[] args) {
        Subject subject = new Subject();
        subject.registerObserver(new ObserverA());
        subject.registerObserver(new ObserverB());
        subject.setState("START");
    }
}

执行结果:

在这里插入图片描述

案例2

使用java.util提供的Observable,Observer类实现案例1。

该方式已在1.9版本中移除,不再推荐使用

实现代码

ConcreteSubject.java

import java.util.Observable;

// 目标对象
public class ConcreteSubject extends Observable {

    private String state;

    public void setState(String state) {
        this.state = state;
        // 表示目标对象已被改变
        setChanged();
        // 通知所有观察者
        notifyObservers();
    }

    public String getState() {
        return state;
    }
}

ObserverA.java

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

/**
 * 观察者A
 *
 * @author Anna.
 * @date 2024/4/25 16:15
 */
public class ObserverA implements Observer {
    @Override
    public void update(Observable o, Object arg) {
        System.out.printf("观察者A接收到消息-state:%s%n", ((ConcreteSubject) o).getState());
    }
}

ObserverB.java

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

// 观察者B
public class ObserverB implements Observer {
    @Override
    public void update(Observable o, Object arg) {
        System.out.printf("观察者B接收到消息-state:%s%n", ((ConcreteSubject) o).getState());
    }
}

TestClient.java

public class TestClient {
    public static void main(String[] args) {
        ConcreteSubject subject = new ConcreteSubject();
        subject.addObserver(new ObserverA());
        subject.addObserver(new ObserverB());

        subject.setState("STOP");
    }
}

执行结果:
在这里插入图片描述

案例3

通过拉方式,实现观察者主动拉取被观察者当前状态

UML

在这里插入图片描述

实现步骤:

  • 创建被观察者Subject,定义状态属性并提供get/set方法
  • 定义观察者接口类,提供拉取状态接口
  • 创建具体的观察者,实现观察者接口,通过持有被观察者的引用,主动拉取被观察者当前状态

实现代码

Subject.java

// 被观察者
public class Subject {
    // 定义当前状态
    private String state;
    public String getState() {
        return state;
    }
    public void setState(String state) {
        this.state = state;
    }
}

Observer.java

// 观察者接口
public interface Observer {
    // 定义拉取信息的接口
    void update();
}

ConcreteObserver.java

// 观察者具体实现
public class ConcreteObserver implements Observer {
    // 定义被观察者,持有被观察者的引用
    private Subject subject;
    public ConcreteObserver(Subject subject) {
        this.subject = subject;
    }
    @Override
    public void update() {
        System.out.printf("观察者主动拉取状态-state:%s%n ", subject.getState());
    }
}

TestClient.java

public class TestClient {
    public static void main(String[] args) {
        // 创建被观察者
        Subject subject = new Subject();
        // 创建观察者
        ConcreteObserver observer = new ConcreteObserver(subject);
        // 修改状态
        subject.setState("RUN");
        // 观察者主动拉取
        observer.update();
    }
}

执行结果:

在这里插入图片描述

gitee源码

git clone https://gitee.com/dchh/JavaStudyWorkSpaces.git

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

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

相关文章

HTML学习笔记(二)

1.HTML图像 图像标签&#xff08;<img>)和源属性&#xff08;src&#xff09; HTML中&#xff0c;图像由<img>标签来定义&#xff0c;<img>是空标签&#xff0c;只包含属性&#xff0c;没有闭合标签。在页面上显示图像需要使用源属性&#xff08;src),src是指…

Docker基本操作 Linux里边操作

docker镜像操作命令: docker images:查看所有镜像; docker rmi:删除镜像 后边可以跟镜像的名字或者id指定要删除的镜像&#xff1b; docker pull:拉取镜像&#xff1b; docker push:推送镜像到服务&#xff1b; docker save :打包镜像 后边有用法; docker load:加载镜像&…

前端JS必用工具【js-tool-big-box】,字符串反转,驼峰转换以及版本号对比

这一小节&#xff0c;我们针对前端工具包&#xff08;npm&#xff09;js-tool-big-box的使用做一些讲解&#xff0c;主要是针对字符串反转&#xff0c;aa-bb-cc转驼峰&#xff0c;以及版本号对比的内容 目录 1 安装和引入 2 字符串反转 3 带有横岗的转驼峰 3.1 转小驼峰 3…

docker-compose编排集成工具,

一、引言 我们知道使用一个 Dockerfile 模板文件可以定义一个单独的应用容器&#xff0c;如果需要定义多个容器就需要服务编排。服务编排有很多种技术方案&#xff0c;今天给大家介绍 Docker 官方产品 Docker-Compose Dockerfile 可以定义一个单独的应用容器&#xff1…

linux,从零安装mysql 8.0.30 ,并且更新至mysql 8.0.36

前言&#xff1a; 系统使用的CentOS 7&#xff0c;系统默认最小安装。 一、基础配置 配置虚拟机IP&#xff0c;需要更改的内容&#xff0c;如下红框中 修改之后 至此&#xff0c;基础配置完成。注意&#xff1a;此处虚拟机网络适配器使用的是&#xff1a;桥接模式 二、软件…

【问题实操】银河麒麟高级服务器操作系统实例,CPU软锁报错触发宕机

1.服务器环境以及配置 处理器&#xff1a; Kunpeng 920 内存&#xff1a; 256G DDR4 整机类型/架构&#xff1a; TaiShan 200 (Model 2280) 内核版本 4.19.90-23.8.v2101.ky10.aarch64 2.问题现象描述 两台搭载麒麟v10 sp1的机器均在系统CPU软锁报错时&#xff0c;触…

Springboot+mybatis升级版(Postman测试)

一、项目结构 1.导入依赖 <?xml version"1.0" encoding"UTF-8"?> <project xmlns"http://maven.apache.org/POM/4.0.0"xmlns:xsi"http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation"http://maven.apach…

高级数据结构与算法期中测试题

一、判断题 1、In dynamic programming algorithms, some results of subproblems have to be stored even they do not compose the optimal solution of a larger problem. T F 解析:T。在动态规划算法中,必须存储子问题的某些结果,因为他们可能需要用来…

区块链技术:NFG元宇宙电商模式

大家好&#xff0c;我是微三云周丽 随着互联网技术的迅猛发展&#xff0c;电子商务行业逐渐崛起为现代经济的重要支柱。而在这一浪潮中&#xff0c;元宇宙电商以其独特的商业模式和巨大的发展潜力&#xff0c;成为行业的新宠。其中&#xff0c;NFG作为元宇宙电商模式的代表&am…

【4110】基于小程序实现的名片管理系统

作者主页&#xff1a;Java码库 主营内容&#xff1a;SpringBoot、Vue、SSM、HLMT、Jsp、PHP、Nodejs、Python、爬虫、数据可视化、小程序、安卓app等设计与开发。 收藏点赞不迷路 关注作者有好处 文末获取源码 技术选型 【后端】&#xff1a;Java 【框架】&#xff1a;spring…

std::ignore的定义

有个全局变量。 把一个变量赋值给ignore&#xff0c;还行&#xff0c;没有拷贝等动作&#xff0c;不用担心性能损失。 VS2017D:\DevTools\VS2017\VC\Tools\MSVC\14.16.27023\include\tuple// STRUCT _Ignore struct _Ignore{ // struct that ignores assignmentstemplate<…

如何利用 GPT 自我提高写作能力

GPT革命&#xff1a;如何用AI技术重新定义写作 介绍 在我们的数字时代&#xff0c;了解自我提高写作的必要性至关重要。 随着 GPT 的兴起&#xff0c;我们正在见证书写的变革时代。 这篇扩展文章深入探讨了 GPT 如何显着提高写作技能。 拥抱未来&#xff1a; 人工智能时代的写…

Oracle 数据迁移同步优化(三)

简述 CloudCanal 最近再次对其 Oracle 源端数据同步进行了一系列优化&#xff0c;这些优化基于用户在真实场景中的反馈&#xff0c;具备很强的生产级别参考意义。 本文将简要介绍这些优化项&#xff0c;希望带给读者一些收获。 增量事件 SCN 乱序问题MISSING_SCN 事件干扰新…

物联网和互联网有什么区别?从多个方面进行探讨——青创智通

工业物联网解决方案-工业IOT-青创智通 物联网和互联网是现代信息技术的两大重要领域&#xff0c;它们在许多方面有着紧密的联系&#xff0c;但也有着明显的区别。本文将从多个方面对物联网和互联网的区别进行探讨。 首先&#xff0c;从定义上来看&#xff0c;互联网是一种全球…

38.WEB渗透测试-信息收集-信息收集-企业信息收集(5)

免责声明&#xff1a;内容仅供学习参考&#xff0c;请合法利用知识&#xff0c;禁止进行违法犯罪活动&#xff01; 内容参考于&#xff1a; 易锦网校会员专享课 上一个内容&#xff1a;37.WEB渗透测试-信息收集-企业信息收集&#xff08;4&#xff09; 上个内容用到了cdn&am…

【赠书活动第3期】《PyTorch 2.0深度学习从零开始学》

1. 赠书活动 《PyTorch 2.0深度学习从零开始学》免费赠书 5 本&#xff0c; 可在本帖评论中简单评论一下本书的优缺点&#xff0c; 或者在本帖评论中简单写一下你学习PyTorch想要达到什么目的&#xff0c; 博主从本帖评论中写得较好的朋友中选5人赠送。 截止日期为2024年5…

leetcode-有效括号序列-94

题目要求 思路 1.使用栈的先进后出的思路&#xff0c;存储前括号&#xff0c;如果st中有对应的后括号与之匹配就说明没问题 2.有两个特殊情况就是字符串第一个就是后括号&#xff0c;这个情况本身就是不匹配的&#xff0c;还有一种是前面的n个字符串本身是匹配的&#xff0c;这…

vue3插槽的name和v-slot的研究

slot可以分为具名插槽和默认,默认插槽name是default 在父组件的template需要些v-slot/#,没写不生效,而在父组件下,而没被template包含的默认放在template且含有#default. 1)没写slot,可以不写template,也可写default的template2)写了name的slot,即使是default也必须些template…

内外网隔离后 内网文件如何导出?

将内外网进行网络隔离后&#xff0c;内网文件如何导出&#xff1f;怎样确保安全的前提下&#xff0c;不影响业务的正常开展&#xff1f;这时候企业就需要采取安全且合规的方法来确保数据的安全性和防止未授权访问。 企业会采用的传统流程是&#xff1a;当文件由内网导出至外部时…

javaWeb项目-校园志愿者管理系统功能介绍

项目关键技术 开发工具&#xff1a;IDEA 、Eclipse 编程语言: Java 数据库: MySQL5.7 框架&#xff1a;ssm、Springboot 前端&#xff1a;Vue、ElementUI 关键技术&#xff1a;springboot、SSM、vue、MYSQL、MAVEN 数据库工具&#xff1a;Navicat、SQLyog 1、SpringBoot框架 …