Java设计模式系列--观察者模式写法2:JDK

news2024/11/26 18:46:40

原文网址:Java设计模式系列--观察者模式写法2:JDK_IT利刃出鞘的博客-CSDN博客

简介

说明

本文用示例介绍观察者模式的一种写法:JDK。

JDK的观察者模式简介

在 Java 中,java.util.Observable 类和 java.util.Observer 接口定义了观察者模式,只要实现这两个接口就可以编写观察者模式。

1. Observable

Observable 类是抽象目标类(被观察者),它有一个 Vector 集合成员变量,用于保存所有要通知的观察者对象,下面来介绍它最重要的 3 个方法。

  • void addObserver(Observer o) 方法:用于将新的观察者对象添加到集合中。
  • void notifyObservers(Object arg) 方法:调用集合中的所有观察者对象的 update方法,通知它们数据发生改变。通常越晚加入集合的观察者越先得到通知。
  • void setChange() 方法:用来设置一个 boolean 类型的内部标志,注明目标对象发生了变化。当它为true时,notifyObservers() 才会通知观察者。

2. Observer

Observer 接口是抽象观察者,它监视目标对象的变化,当目标对象发生变化时,观察者得到通知,并调用 update 方法,进行相应的工作。

实例

本处使用一个贴近真实场景的案例:订单取消时,要有一系列操作,比如:账户业务需要给用户退钱、库存业务需要给商品退回数量。

在这个场景中,取消订单就是被观察者,账户业务和库存业务是观察者。

项目结构

业务数据类 

取消订单时,主题会将这个数据给到感兴趣的观察者。

package com.knife.designPattern.jdk.bo;

import lombok.Data;

@Data
public class CancelOrderBO {
    private String orderNo;
}

主题

package com.knife.designPattern.jdk.subject;
 
import com.knife.designPattern.jdk.bo.CancelOrderBO;

import java.util.Observable;
 
public class CancelOrderSubject extends Observable {

    public void process(CancelOrderBO cancelOrderBO) {
        super.setChanged(); //changed  = true
        super.notifyObservers(cancelOrderBO);
    }
}
 

观察者

账户业务观察者

package com.knife.designPattern.jdk.observer;

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

/**
 * 具体观察者: 账户业务
 */
public class AccountCancelOrderObserver implements Observer {

    @Override
    public void update(Observable o, Object arg) {
        System.out.println("账户业务开始处理订单取消。接收到的消息:" + arg);
    }
}

仓库业务观察者

package com.knife.designPattern.jdk.observer;

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

/**
 * 具体观察者: 库存业务
 */
public class StorageCancelOrderObserver implements Observer {
    @Override
    public void update(Observable o, Object arg) {
        System.out.println("库存业务开始处理订单取消。接收到的消息:" + arg);
    }
}

主题持有者

只有主题还不行,需要有一个地方去调用它,添加一个主题持有者

package com.knife.designPattern.jdk.subject;

import com.knife.designPattern.jdk.bo.CancelOrderBO;
import com.knife.designPattern.jdk.observer.AccountCancelOrderObserver;
import com.knife.designPattern.jdk.observer.StorageCancelOrderObserver;

public class SubjectHolder {
    private static final CancelOrderSubject instance = init();

    private SubjectHolder() {
    }

    private static CancelOrderSubject init() {
        // 创建被观察者
        CancelOrderSubject orderCancelSubject = new CancelOrderSubject();

        // 创建观察者
        AccountCancelOrderObserver accountCancelOrderObserver =
                new AccountCancelOrderObserver();
        StorageCancelOrderObserver storageCancelOrderObserver =
                new StorageCancelOrderObserver();

        // 添加观察者,这样被观察者有数据时观察者就能感知到
        orderCancelSubject.addObserver(accountCancelOrderObserver);
        orderCancelSubject.addObserver(storageCancelOrderObserver);
        return orderCancelSubject;
    }

    public static void process(CancelOrderBO cancelOrderBO) {
        instance.process(cancelOrderBO);
    }
}

测试 

测试类

package com.knife.designPattern.jdk.controller;

import com.knife.designPattern.jdk.bo.CancelOrderBO;
import com.knife.designPattern.jdk.subject.SubjectHolder;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@Api(tags = "订单")
@RestController
@RequestMapping("order")
public class OrderController {
    @ApiOperation("取消订单")
    @PostMapping("cancel")
    public String cancel(@RequestBody CancelOrderBO cancelOrderBO) {
        SubjectHolder.process(cancelOrderBO);
        return "success";
    }
}

访问接口

启动项目后,访问Knife4j(接口文档)的地址:http://localhost:8080/doc.html

(当然,你用postman也完全可以)

结果

库存业务开始处理订单取消。接收到的消息:CancelOrderBO(orderNo=666)
账户业务开始处理订单取消。接收到的消息:CancelOrderBO(orderNo=666)

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Elsevier: Expert Systems With Applications 经验分享

目录 序时间线投稿返稿录用模板下载链接 序 这是一篇Elsevier旗下Expert Systems With Applications(ESWA)期刊的投稿经验分享。虽然是ESWA,但对于Elsevier旗下的其它期刊也适用,他们都可以用一套模板。 需要注意的是不同期刊会有一些特别的要求&#…

13 直接存储器访问DMA(基于STM32HAL库)

目录 DMA-直接存储器访问控制器 DMA概览 DMA的作用 DMA框图 DMA外设要点概括 DMA功能对比 STMF10x DMA具体内容 DMA主要特性 DMA中断 DMA请求映像 DMA的使用步骤 HAL库中的DMA功能实例 句柄结构体介绍(以DMA为例) 外设初始化结构体介绍 具体…

多元回归预测 | Matlab基于粒子群算法优化深度置信网络(PSO-DBN)的数据回归预测,matlab代码回归预测,多变量输入模型

文章目录 效果一览文章概述部分源码参考资料效果一览 文章概述 多元回归预测 | Matlab基于基于粒子群算法优化深度置信网络(PSO-DBN)的数据回归预测,matlab代码回归预测,多变量输入模型,多变量输入模型 评价

聊聊不同集群的微服务如何通过feign调用

前言 之前业务部门的某项目微服务调用关系如下图 后因业务改造需要,该项目需要将服务A部署到另外一个集群,但服务A仍然需要能调用到服务B,调用关系如下图 之前调用方式是负责服务B的开发团队提供相应的feign客户端包给到服务A开发团队&…

三种Linux内核代码在线阅读工具

记录一下 1 . 可在线阅读uboot,kernel,busybox(rootfs),可搜索字符串,函数跳 https://lxr.missinglinkelectronics.com/ 界面如下: 2. 显示界面跟代码编辑器很像,同样可以函数跳转 https://elixir.boot…

如何让罗技29方向盘像视频中的那样转动起来?

​​​​​​​[vlog]Autoware Carla G29 自动驾驶仿真_哔哩哔哩_bilibili 话接上文,在我之前一篇博客中已经讲解了如何给罗技29方向盘装上力反馈,也就是在拨动方向盘的时候感觉有一个力组织你过度的拨动方向盘,其实它真正的用处是用于实现对…

【Web3】认识区块链

目录 区块链特征 区块链类型 区块链的概念 区块链特征 去中心化:区块链是由一个分布在多个参与者之间的网络组成,没有中央机构或中介控制整个系统。所有参与者共同维护和验证账本的完整性,减少了单点故障和集中式控制的风险。共识机制&…

【HTTPS】采用的加密策略, 什么是中间人攻击? 什么是证书?

文章目录 前言一、认识 HTTPS 协议1, 对称加密2, 非对称加密 二、HTTPS 加密策略1, 只采用对称加密 : 不安全2, 引入非对称加密3, 中间人攻击之偷梁换柱4, 引入证书4.1 什么是证书4.2, 证书如何能解决"中间人攻击" 总结 前言 各位读者好, 我是小陈, 这是我的个人主页…

日历与时钟

目录 公历 黑色星期五 生物韵律 公历 在公历中,当年份为4的整数倍,但不是100的整数倍时,会出现闰年的现象。 y40 mod(y,4) 0 && mod(y,100)||mod(y,400)0 输出当时的年、月、日、时、分、秒 f%6d %6d %6d %6d %6d %9.3f\n cclock …

MySQL学习基础篇(八)---聚合函数

MySQL学习基础篇(八)—聚合函数 聚合(或聚集、分组)函数,它是对一组数据进行汇总的函数,输入的是一组数据的集合,输出的是单个值。 1. 聚合函数介绍 什么是聚合函数:聚合函数作用于一组数据,…

前端实战——尚品汇(网页开发)

/* 基础设置 */ .container {width: 1190px;margin: 0 auto; } /* #region顶部导航条start */ .topbar {height: 30px;background-color: #ececec; } .welcome {height: 30px;line-height: 30px;font-size: 0;color: #666; } .welcome span,.welcome a {font-size: 12px; } .we…

AIGC - Stable Diffusion WebUI 图像生成工具的环境配置

欢迎关注我的CSDN:https://spike.blog.csdn.net/ 本文地址:https://spike.blog.csdn.net/article/details/131528224 Stable Diffusion WebUI 是一款基于深度学习的图像生成工具,根据用户的输入文本或图像,生成高质量的新图像&…

关于VMware虚拟空间的创建、Linux系统的安装

文章目录 前言一、Windows用户安装VMware软件1.1 下载VMware1.2 正常安装VMware后,该软件是要收费的,但是下面的链接可以让你使用很久 二、Mac用户安装VMware软件2.1 下载macOS版本:VMware Fusion2.2 正常安装VMware后,该软件是要…

「2024」预备研究生mem-形式逻辑强化:推矛盾

一、推矛盾 易错题:重点 重点: 二、课后题 三、每日一练

新版本vscode使用配置文件功能,解决不同项目使用不同的插件

如果你同时有vue2,vue3的项目。一定会遇到插件的问题。因为vue2项目插件是使用vetur的,vue3是使用volar的。 以前vscode为了在不同项目中能使用不同的配置文件,是使用工作区的概念去解决的,但是比较复杂而且不好用。 现在新版本的vscode&…

【温故而知新】Android架构模式

Android项目工程中常用的架构模式有MVC, MVP, MVVM以及现在新出的MVI。 下面一起温故而知新。 MVC MVC(Model-View-Controller)是一种在Android应用程序中使用的架构模式,用于实现松耦合、可测试和可维护的应用程序。 MVC架构模式包括三个…

高级篇十六、多版本并发控制(重要)

目录 1、什么是MVCC2、快照读与当前读2.1 快照读2.2 当前读 3、复习3.1 隔离级别3.2 隐藏字段、Undo Log版本链 4、MVCC实现原理之ReadView4.1 什么是ReadView? 1、什么是MVCC MVCC (Multiversion Concurrency Control),多版本并…

Django之ORM的锁,开启事务,Ajax

一、行锁 select_for_update(nowaitFalse, skip_lockedFalse) 注意必须用在事务里面,至于如何开启事务,我们看下面的事务一节 Book.objects.select_for_update().filter(nid3) # 锁住nid3的行select_for_update中的两个参数了解即可,因为在…

机器学习入门

AI人工智能 ANI 弱人工智能,狭义人工智能,指的是一种针对特定任务或领域进行优化的人工智能,例如语音识别、图像识别、自然语言处理、推荐系统 AGI 通用人工智能,强人工智能, ASI 超级人工智能,超人工智…

Erupt框架学习

Erupt框架学习 Erupt框架Erupt简介学习EruptEruptFieldErupt的逻辑删除Erupt的自定义按钮多数据源配置 Erupt框架 Erupt简介 最近因为工作所以接触到了一个低代码框架Erupt。这是一个通用的配置管理框架,主打就是零前端代码,急速开发通用管理框架。 Er…