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

news2024/11/15 20:37:59

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

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

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

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

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

不使用观察者模式

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 接口
扩展性差,增加新模块需要修改商品类好,新增模块只需实现观察者接口并注册即可
维护性差,修改商品类可能导致其他模块发生问题好,模块独立,修改不会影响其他模块
符合设计原则不符合开闭原则符合开闭原则

结论

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

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

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

相关文章

My_SQL day3

知识点&#xff1a;约束 1.dafault 默认约束 2.not null 非空约束 3.unique key 唯一约束 4.primary key 主键约束 5.anto_increment 自增长约束 6.foreign key 外键约束 知识点&#xff1a;表关系 1.一对一 2.一对多 3.多对多 知识点&#xff1a;约束 1.default 默认约束 …

caozha-CEPCS(新冠肺炎疫情防控系统)

caozha-CEPCS&#xff0c;是一个基于PHP开发的新冠肺炎疫情防控系统&#xff0c;CEPCS&#xff08;全称&#xff1a;COVID-19 Epidemic Prevention and Control System&#xff09;&#xff0c;可以应用于单位、企业、学校、工业园区、村落等等。小小系统&#xff0c;希望能为大…

深度学习推荐系统的工程实现

参考自《深度学习推荐系统》——王喆&#xff0c;用于学习和记录。 介绍 之前章节主要从理论和算法层面介绍了推荐系统的关键思想。但算法和模型终究只是“好酒”&#xff0c;还需要用合适的“容器”盛载才能呈现出最好的味道&#xff0c;这里的“容器”指的就是实现推荐系统…

2024 年(第 7 届)“泰迪杯”数据分析技能赛B 题 特殊医学用途配方食品数据分析 完整代码 结果 可视化分享

一、背景特殊医学用途配方食品简称特医食品&#xff0c;是指为满足进食受限、消化吸收障碍、代谢素乱或者特定疾病状态人群对营养素或者膳食的特殊需要&#xff0c;专门加工配置而成的配方食品&#xff0c;包括0月龄至12月龄的特殊医学用途婴儿配方食品和适用于1岁以上的特殊医…

Ubuntu 的 ROS 2 操作系统安装与测试

引言 机器人操作系统&#xff08;ROS, Robot Operating System&#xff09;是一种广泛应用于机器人开发的开源框架&#xff0c;提供了丰富的库和工具&#xff0c;支持开发者快速构建、控制机器人并实现智能功能。 当前&#xff0c;ROS 2 的最新长期支持版本为 Humble Hawksbil…

SQL面试题——奔驰SQL面试题 车辆在不同驾驶模式下的时间

SQL面试题——奔驰SQL面试题 我们的表大致如下 CREATE TABLE signal_log( vin STRING COMMENTvehicle frame id, signal_name STRING COMMENTfunction name, signal_value STRING COMMENT signal value , ts BIGINT COMMENTevent timestamp, dt STRING COMMENTformat yyyy-mm…

pytest执行用例时从conftest.py抛出ModuleNotFoundError:No module named ‘XXX‘异常的解决办法

网上各种各样的&#xff1a;1、关于_pycache_影响conftest的&#xff1b;2、目录路径的&#xff1b;3、配置环境的&#xff1b; 4、发现自己是powershell后&#xff0c;设置环境&#xff1a; $env:environment"local" 仍然报错的&#xff1a;5、最后发现是自己的 …

JAVA:探索 EasyExcel 的技术指南

1、简述 在 Java 开发中&#xff0c;Excel 文件的读写操作是一项常见的需求。阿里巴巴开源的 EasyExcel 提供了一种高效、简洁的解决方案&#xff0c;特别是在处理大规模数据时表现尤为突出。本文将详细介绍 EasyExcel 的优缺点、应用场景&#xff0c;并通过实例展示其基本用法…

Python自动化小技巧24——实现自动化输出模板表格报告

背景 很多人拿到数据excel文件&#xff0c;然后要写报告&#xff0c;做表格&#xff0c;要各种计算&#xff0c;各种排序&#xff0c;分组聚合&#xff0c;数据透视&#xff0c;然后合并单元格&#xff0c;添加边框&#xff0c;加粗&#xff0c;添加显示规则&#xff0c;添加数…

C# 通俗易懂的介绍基础知识(七)——栈Stack(从日常生活开始讲解)

目录 一、前言 二、栈是排列方式 三、栈的单词 四、程序中的栈 五、栈的方法 1.声明并初始化栈 2.往栈里放东西&#xff08;学名&#xff1a;入栈&#xff09; 3.从栈往外拿东西 &#xff08;学名&#xff1a;出栈&#xff09; 4.清空栈 5.遍历 Stack 6.获取Stack的长…

Vue全栈开发旅游网项目(10)-用户管理后端接口开发

1.异步用户登录\登出接口开发 1.设计公共响应数据类型 文件地址&#xff1a;utils/response404.py from django.http import JsonResponseclass BadRequestJsonResponse(JsonResponse):status_code 400def __init__(self, err_list, *args, **kwargs):data {"error_c…

PostgreSQL中如果有Left Join的时候索引怎么加

在PostgreSQL中&#xff0c;当你的查询包含多个LEFT JOIN和WHERE条件时&#xff0c;合理地添加索引可以显著提高查询性能。以下是一些具体的优化步骤和建议&#xff1a; 1. 分析查询 使用 EXPLAIN ANALYZE 命令分析你的查询&#xff0c;了解查询的执行计划&#xff0c;识别出连…

A027-基于Spring Boot的农事管理系统

&#x1f64a;作者简介&#xff1a;在校研究生&#xff0c;拥有计算机专业的研究生开发团队&#xff0c;分享技术代码帮助学生学习&#xff0c;独立完成自己的网站项目。 代码可以查看文章末尾⬇️联系方式获取&#xff0c;记得注明来意哦~&#x1f339; 赠送计算机毕业设计600…

Vue的基础使用

一、为什么要学习Vue 1.前端必备技能 2.岗位多&#xff0c;绝大互联网公司都在使用Vue 3.提高开发效率 4.高薪必备技能&#xff08;Vue2Vue3&#xff09; 二、什么是Vue 概念&#xff1a;Vue (读音 /vjuː/&#xff0c;类似于 view) 是一套 构建用户界面 的 渐进式 框架…

Innovus Flexible H-tree and Multi-tap Clock Flow Lab实操系列教程(Day1)

我们都知道时钟树综合在数字IC后端实现中的重要性。做clock tree主要有传统clock tree做法&#xff0c;H tree&#xff0c;Flexible H-tree&#xff0c;fishbone等做法。接下去小编将拿cadence官方的这份Innovus Flexible H-tree and Multi-Tap Clock Flow和对应的lab data来做…

【MySQL】MySQL数据库安装以及报错处理技巧

前言&#xff1a; 本节内容讲述在Ubuntu环境下怎么进行MySQL的安装。 以及一些安装过程中遇到的报错如何处理的问题。 ps:注意&#xff0c; 本篇文章不是图形化界面的MySQL安装教程哦。想要安装图形化界面的MySQL的友友们可以另寻资源了。 目录 更新软件包列表 安装M…

ISP——你可以从这里起步(二)

接上一篇&#xff0c;上一篇是原理篇&#xff0c;这一篇是实战篇&#xff0c;为了实现下面框图中的不完美ISP。 第一章 做一张RAW图自己用 不是所有的人都能获得raw图&#xff0c;即使获得了raw图也需要对应的sensor参数才能把它用起来&#xff0c;所以我找了一条野路子可以把…

CTF攻防世界小白刷题自学笔记14

fileclude&#xff0c;难度&#xff1a;1&#xff0c;方向&#xff1a;Web 题目来源:CTF 题目描述:好多file呀&#xff01; 给一下题目链接&#xff1a;攻防世界Web方向新手模式第17题。 打开一看&#xff0c;这熟悉的味道&#xff0c;跟上一篇文章基本一摸一样的&#xff…

CTFHub每日练习

文章目录 技能树CTF Web信息泄露目录遍历PHPINFO备份文件下载网站源码bak文件vim缓存.DS_Store Git泄露Logstash index方法一方法二 密码口令弱口令 技能树 CTF Web 信息泄露 目录遍历 PHPINFO 备份文件下载 网站源码 当开发人员在线上环境中对源代码进行了备份操作&#x…

使用CNN进行验证码识别:深度学习与图像预处理教程

验证码&#xff08;CAPTCHA&#xff09;广泛用于区分人类和自动化程序&#xff08;如机器人&#xff09;&#xff0c;通常由扭曲的字母、数字或符号组成。为了实现验证码的自动识别&#xff0c;深度学习尤其是卷积神经网络&#xff08;CNN&#xff09;非常有效。本文将带你一起…