观察者模式 vs 不使用观察者模式:商品库存变化的通知

在软件开发中,观察者模式是一种非常常见的设计模式,用于解决对象间的依赖关系。当一个对象的状态发生改变时,需要通知其他相关对象,确保它们的状态也随之更新。本文将通过一个具体的业务场景——商品库存变化,来对比在使用和不使用观察者模式时的实现方式,从而帮助你更好地理解观察者模式的优势。

业务场景:商品库存变化通知

假设我们正在开发一个电商系统,其中涉及到多个模块对商品库存信息的依赖:

  • 商品详情页:展示商品的库存数量。
  • 购物车:展示用户购物车中商品的库存状态。

当商品库存数量发生变化时,我们需要通知这些模块进行同步更新。如果不使用观察者模式,可能会导致代码耦合性较强,难以扩展和维护。而使用观察者模式,则能提供一个解耦的设计,使得各个模块之间的通信更加简洁和高效。

不使用观察者模式

1. 直接调用更新方法

在没有观察者模式的情况下,当商品库存发生变化时,我们可能会直接在商品类中手动调用商品详情页和购物车的更新方法。这会导致商品类和其他模块(商品详情页、购物车)之间存在紧密的耦合。

// 商品类(没有观察者模式)
class Product {
    private int stockQuantity;  // 库存数量
    private ProductDetailPage detailPage;
    private ShoppingCart shoppingCart;

    public Product(ProductDetailPage detailPage, ShoppingCart shoppingCart) {
        this.detailPage = detailPage;
        this.shoppingCart = shoppingCart;
    }

    // 设置库存数量并更新其他模块
    public void setStockQuantity(int stockQuantity) {
        this.stockQuantity = stockQuantity;
        System.out.println("商品库存更新为: " + stockQuantity);

        // 手动通知商品详情页和购物车更新库存
        detailPage.update(stockQuantity);
        shoppingCart.update(stockQuantity);
    }
}

2. 商品详情页和购物车

商品详情页和购物车类会有一个 update 方法,用于接收商品库存的变化并更新显示。

// 商品详情页
class ProductDetailPage {
    public void update(int stockQuantity) {
        System.out.println("商品详情页更新库存显示为: " + stockQuantity);
    }
}

// 购物车
class ShoppingCart {
    public void update(int stockQuantity) {
        System.out.println("购物车更新库存显示为: " + stockQuantity);
    }
}

3. 测试类

在这个例子中,我们直接在商品类中管理了商品详情页和购物车的更新逻辑。

public class WithoutObserverPattern {
    public static void main(String[] args) {
        ProductDetailPage detailPage = new ProductDetailPage();
        ShoppingCart shoppingCart = new ShoppingCart();
        
        Product product = new Product(detailPage, shoppingCart);
        product.setStockQuantity(10);
        product.setStockQuantity(5);
    }
}

运行结果

商品库存更新为: 10
商品详情页更新库存显示为: 10
购物车更新库存显示为: 10
商品库存更新为: 5
商品详情页更新库存显示为: 5
购物车更新库存显示为: 5

存在的问题

  1. 耦合性强:商品类直接依赖于商品详情页和购物车,若以后新增其他依赖库存信息的模块,需要修改商品类,违反了开闭原则(OCP)。
  2. 扩展困难:若有多个模块依赖库存变化,每个模块都需要在商品类中手动注册,增加了维护难度。
  3. 难以维护:随着项目的增长,代码会变得越来越复杂,修改其中的一个部分可能会引发连锁反应,增加出错的风险。

使用观察者模式

1. 观察者接口

首先,我们定义观察者接口 Observer,其中包含一个 update 方法,用于接收商品库存变化的通知。

// 定义观察者接口
interface Observer {
    void update(int stockQuantity);  // 更新库存数量的方法
}

2. 被观察者类(商品类)

接下来,我们定义商品类 Product,它会维护一个观察者列表,并在库存变化时通知所有观察者。

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

// 定义被观察的商品类(Subject)
class Product {
    private List<Observer> observers = new ArrayList<>();  // 观察者列表
    private int stockQuantity;  // 库存数量

    // 添加观察者
    public void addObserver(Observer observer) {
        observers.add(observer);
    }

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

    // 通知所有观察者
    private void notifyObservers() {
        for (Observer observer : observers) {
            observer.update(stockQuantity);  // 更新每个观察者
        }
    }

    // 设置库存数量,并通知观察者
    public void setStockQuantity(int stockQuantity) {
        this.stockQuantity = stockQuantity;
        System.out.println("商品库存更新为: " + stockQuantity);
        notifyObservers();  // 通知所有观察者
    }
}

3. 具体观察者类(商品详情页和购物车)

商品详情页和购物车分别实现观察者接口,当商品库存变化时,它们会接收到更新通知,并更新各自的库存显示。

// 商品详情页(观察者)
class ProductDetailPage implements Observer {
    @Override
    public void update(int stockQuantity) {
        System.out.println("商品详情页更新库存显示为: " + stockQuantity);
    }
}

// 购物车(观察者)
class ShoppingCart implements Observer {
    @Override
    public void update(int stockQuantity) {
        System.out.println("购物车更新库存显示为: " + stockQuantity);
    }
}

4. 测试类

在测试类中,我们通过 addObserver 方法将商品详情页和购物车添加为观察者,商品库存更新时,它们会自动接收到通知并更新显示。

public class WithObserverPattern {
    public static void main(String[] args) {
        Product product = new Product();

        ProductDetailPage detailPage = new ProductDetailPage();
        ShoppingCart shoppingCart = new ShoppingCart();

        // 注册观察者
        product.addObserver(detailPage);
        product.addObserver(shoppingCart);

        // 设置库存数量,通知观察者
        product.setStockQuantity(10);
        product.setStockQuantity(5);
    }
}

运行结果

商品库存更新为: 10
商品详情页更新库存显示为: 10
购物车更新库存显示为: 10
商品库存更新为: 5
商品详情页更新库存显示为: 5
购物车更新库存显示为: 5

优势

  1. 低耦合性:商品类和观察者类之间只通过接口进行依赖,任何一个模块的变化不会影响到其他模块的实现。
  2. 可扩展性强:当需要增加新的依赖商品库存的模块时,只需实现 Observer 接口并注册为观察者,无需修改商品类。
  3. 符合开闭原则:商品类可以在不修改的情况下增加新的观察者,保持代码的稳定性。

对比总结

特性不使用观察者模式使用观察者模式
耦合性高,商品类直接依赖多个模块(商品详情页、购物车等)低,商品类只依赖于 Observer 接口
扩展性差,增加新模块需要修改商品类好,新增模块只需实现观察者接口并注册即可
维护性差,修改商品类可能导致其他模块发生问题好,模块独立,修改不会影响其他模块
符合设计原则不符合开闭原则符合开闭原则

结论

通过对比可以看出,观察者模式解决了不使用观察者模式时存在的耦合性高、扩展性差的问题,使得系统更加灵活、可维护和可扩展。在需要处理多个模块之间的依赖关系时,观察者模式提供了一种简洁且有效的方式来解耦不同模块之间的关系。
说点大白话就是采用观察者模式是定义了一个统一的接口,不同的观察者都实现这个接口。然后在被观察的目标中维护一个观察者的集合,若是有改变则指需要增加或者删除对应的观察者即可

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

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

相关文章

微信小程序——01开发前的准备和开发工具

文章目录 一、开发前的准备1注册小程序账号2安装开发者工具 二、开发者工具的使用1创建项目2 工具的使用3目录结构4各个页面之间的关系5 权限管理6提交审核和发布 一、开发前的准备 开发前需要进行以下准备&#xff1a; 1 注册小程序账号2激活邮箱3 信息登记4 登录小程序管理后…

SQL慢查询优化方式

目录 一、SQL语句优化 1.避免使用 SELECT * &#xff0c;而是具体字段 2.避免使用 % 开头的 LIKE 的查询 3.避免使用子查询&#xff0c;使用JOIN 4.使用EXISTS代替IN 5.使用LIMIT 1优化查询 6.使用批量插入、优化INSERT操作 7.其他方式 二、SQL索引优化 1.在查询条件…

【51单片机】LCD1602液晶显示屏

学习使用的开发板&#xff1a;STC89C52RC/LE52RC 编程软件&#xff1a;Keil5 烧录软件&#xff1a;stc-isp 开发板实图&#xff1a; 文章目录 LCD1602存储结构时序结构 编码 —— 显示字符、数字 LCD1602 LCD1602&#xff08;Liquid Crystal Display&#xff09;液晶显示屏是…

git入门环境搭建和gui使用

git下载 git官网地址&#xff1a;https://git-scm.com/ 如果没有魔法的话&#xff0c;官网这个地址能卡死你 这里给个国内的git镜像链接 git历史版本镜像链接 然后一路next 默认路径 默认勾选就行。 今天就写到这吧&#xff0c;11点多了该睡了&#xff0c;&#xff0c;&#…

python调用MySql详细步骤

一、下载MySql MySQL :: Download MySQL Installerhttps://dev.mysql.com/downloads/windows/installer/8.0.html点击上面链接&#xff0c;进入MySQL8.0的下载页面&#xff0c;选择离线安装包下载。 不需要登陆&#xff0c;直接点击下方的 No thanks,just start my download. …

【go从零单排】通道select、通道timeout、Non-Blocking Channel Operations非阻塞通道操作

&#x1f308;Don’t worry , just coding! 内耗与overthinking只会削弱你的精力&#xff0c;虚度你的光阴&#xff0c;每天迈出一小步&#xff0c;回头时发现已经走了很远。 &#x1f4d7;概念 select 语句是 Go 的一种控制结构&#xff0c;用于等待多个通道操作。它类似于 s…

FPGA实现PCIE采集电脑端视频转SFP光口万兆UDP输出,基于XDMA+GTX架构,提供2套工程源码和技术支持

目录 1、前言工程概述免责声明 2、相关方案推荐我已有的PCIE方案10G Ethernet Subsystem实现万兆以太网物理层方案 3、PCIE基础知识扫描4、工程详细设计方案工程设计原理框图电脑端视频PCIE视频采集QT上位机XDMA配置及使用XDMA中断模块FDMA图像缓存UDP视频组包发送UDP协议栈MAC…

C++数据结构算法学习

C ,orient(面向) object , object entity(实体) Visible(可见的) or invisible(不可见) 变量用来保存数据 objects attribute(属性) services(服务) C STL 容器 vector, list&#xff08;&#xff09; vector底层是数组&#xff0c;类似双向链表和list底层 map/s…

基于Java Springboot图书馆管理系统

一、作品包含 源码数据库文档全套环境和工具资源部署教程 二、项目技术 前端技术&#xff1a;Html、Css、Js 数据库&#xff1a;MySQL 后端技术&#xff1a;Java、Spring Boot、MyBatis 三、运行环境 开发工具&#xff1a;IDEA/eclipse 数据库&#xff1a;MySQL8.0 数据…

三周精通FastAPI:37 包含 WSGI - Flask,Django,Pyramid 以及其它

官方文档&#xff1a;https://fastapi.tiangolo.com/zh/advanced/wsgi/ 包含 WSGI - Flask&#xff0c;Django&#xff0c;其它 您可以挂载多个 WSGI 应用&#xff0c;正如您在 Sub Applications - Mounts, Behind a Proxy 中所看到的那样。 为此, 您可以使用 WSGIMiddlewar…

gdb调试redis。sudo

1.先启动redis-server和一个redis-cli。 2.ps -aux|grep reids查看redis相关进程。 3.开始以管理员模式附加进程调试sudo gdb -p 2968.注意这里不能不加sudo&#xff0c;因为Redis 可能以 root 用户启动&#xff0c;普通用户无法附加到该进程。否则就会出现可能下列情形&#…

Python安装(ubuntu)

一&#xff1a;安装指定版本的python python3 --version直接返回ubuntu自带的3.8.10的版本 radarswradarsw-Precision-5560:~$ python3 --version Python 3.8.10通过指令直接安装&#xff0c;会报错如下; radarswradarsw-Precision-5560:~$ sudo apt install python3.11 正在…

在 Oracle Linux 8.9 上安装Oracle Database 23ai 23.5

在 Oracle Linux 8.9 上安装Oracle Database 23ai 23.5 1. 安装 Oracle Database 23ai2. 连接 Oracle Database 23c3. 重启启动后&#xff0c;手动启动数据库4. 重启启动后&#xff0c;手动启动 Listener5. 手动启动 Pluggable Database6. 自动启动 Pluggable Database7. 设置开…

在VMware虚拟机环境下识别U盘

文章目录 前言一、在自己的计算机上&#xff08;非虚拟机&#xff09;按【winR】键→输入【services.msc】→点击【确定】二、找到服务名称为【VMware USB Arbitration Service】确保为启动状态三、VMware虚拟机设置四、启动虚拟机系统&#xff0c;插入U盘查看是否能识别到U盘 …

数据库范式、MySQL 架构、算法与树的深入解析

一、数据库范式 在数据库设计中&#xff0c;范式是一系列规则&#xff0c;用于确保数据的组织和存储具有良好的结构、完整性以及最小化的数据冗余。如果不遵循范式设计&#xff0c;数据可能会以平铺式罗列&#xff0c;仅使用冒号、分号等简单分隔。这种方式存在诸多弊端&#…

Leetcode 存在重复元素II

这段代码的算法思想可以用以下步骤来解释&#xff1a; 算法思想 使用哈希表&#xff08;HashMap&#xff09;存储每个元素的索引&#xff1a; 遍历数组 nums 时&#xff0c;使用一个 HashMap 来记录每个元素的值和它的索引位置。这样可以快速查找之前出现过的相同元素的索引。…

Vue3.js - 一文看懂Vuex

1. 前言 Vuex 是 Vue.js 的官方状态管理库&#xff0c;用于在 Vue 应用中管理组件之间共享的状态。Vuex 适用于中大型应用&#xff0c;它将组件的共享状态集中管理&#xff0c;可以避免组件间传递 props 或事件的复杂性。 2. 核心概念 我们可以将Vuex想象为一个大型的Vue&…

面试编程题目(一)细菌总数计算

题目如图&#xff1a; 第一题&#xff1a; import lombok.AllArgsConstructor; import lombok.Data;import java.util.Arrays; import java.util.Collections; import java.util.List;/*** description: 细菌实体类* author: zhangmy* Version: 1.0* create: 2021-03-30 11:2…

基于Qt/C++与OpenCV库 实现基于海康相机的图像采集和显示系统(工程源码可联系博主索要)

本文将梳理一个基于 Qt 和 OpenCV 实现的海康相机图像采集 Demo。该程序能够实现相机连接、参数设置、图像采集与显示、异常处理等功能&#xff0c;并通过 Qt 界面展示操作结果。 1. 功能概述 该程序使用 Qt 的 GUI 作为界面&#xff0c;OpenCV 作为图像处理库&#xff0c;通…

网络基础Linux

目录 计算机网络背景 网络发展 认识 "协议" 网络协议初识 OSI七层模型 TCP/IP五层(或四层)模型 网络传输基本流程 网络传输流程图 ​编辑 数据包封装和分用 网络中的地址管理 认识IP地址 认识MAC地址 笔记&#xff08;画的图&#xff09; 协议&#x…