设计模式实战:在线购物系统的设计与实现

简介

本篇文章将介绍如何设计一个在线购物系统,系统包括购物车、订单处理、支付等功能。我们将通过这一项目,应用组合模式、命令模式、策略模式和观察者模式来解决具体的设计问题。

问题描述

设计一个在线购物系统,用户可以浏览商品、将商品添加到购物车、提交订单并完成支付。系统需要支持多种支付方式,并且能够在订单状态变化时通知用户。

设计分析

业务流程说明

整个在线购物系统的业务流程如下:

  1. 用户浏览商品并将商品添加到购物车。
  2. 用户查看购物车并确认商品。
  3. 用户提交订单,系统生成订单。
  4. 用户选择支付方式并进行支付。
  5. 系统处理支付请求,完成支付。
  6. 支付完成后,系统更新订单状态,并通知用户。

流程图

浏览商品
添加商品到购物车
查看购物车
确认商品
提交订单
选择支付方式
支付
支付成功
更新订单状态
通知用户

模块依赖关系图

ShoppingCart
Order
PaymentContext
PaymentStrategy
Observer

模式选择

购物车设计
  • 模式选择:组合模式
  • 原因:组合模式适用于将对象组合成树形结构以表示部分-整体层次。购物车中的商品可以看作树结构中的叶子节点,而购物车本身可以看作树的根节点。使用组合模式能够方便地处理购物车中商品的添加和总价计算。
订单处理设计
  • 模式选择:命令模式
  • 原因:命令模式用于将请求封装成对象,使得可以用不同的请求、队列或者日志来参数化其他对象。订单处理需要支持提交和取消操作,使用命令模式可以将这些操作封装成独立的对象,从而使系统更灵活和易于扩展。
支付方式设计
  • 模式选择:策略模式
  • 原因:策略模式定义了一系列算法,并将每个算法封装起来,使它们可以互换。系统需要支持多种支付方式,使用策略模式可以使支付方式的实现更加灵活,方便添加新的支付方式而不影响现有代码。
通知用户设计
  • 模式选择:观察者模式
  • 原因:观察者模式定义了对象之间的一对多依赖,当一个对象改变状态时,其所有依赖者都会收到通知并自动更新。订单状态变化时需要通知用户,使用观察者模式可以实现这一需求,确保用户及时获取订单状态的更新。

详细设计与实现

数据模型

组合模式(购物车设计)
import java.util.ArrayList;
import java.util.List;// 产品接口
interface ProductComponent {double getPrice();
}// 商品类
class Product implements ProductComponent {private String name;private double price;public Product(String name, double price) {this.name = name;this.price = price;}@Overridepublic double getPrice() {return this.price;}public String getName() {return name;}
}// 购物车类
class ShoppingCart implements ProductComponent {private List<ProductComponent> items = new ArrayList<>();public void addItem(ProductComponent item) {items.add(item);}public void removeItem(ProductComponent item) {items.remove(item);}@Overridepublic double getPrice() {return items.stream().mapToDouble(ProductComponent::getPrice).sum();}public List<ProductComponent> getItems() {return items;}
}
命令模式(订单处理)
// 订单类
class Order {private String status;public void submit() {this.status = "Submitted";notifyObservers();}public void cancel() {this.status = "Canceled";notifyObservers();}public String getStatus() {return status;}private List<Observer> observers = new ArrayList<>();public void addObserver(Observer observer) {observers.add(observer);}public void notifyObservers() {for (Observer observer : observers) {observer.update("Order status changed to " + status);}}
}// 命令接口
interface OrderCommand {void execute();
}// 提交订单命令
class SubmitOrderCommand implements OrderCommand {private Order order;public SubmitOrderCommand(Order order) {this.order = order;}@Overridepublic void execute() {order.submit();}
}// 取消订单命令
class CancelOrderCommand implements OrderCommand {private Order order;public CancelOrderCommand(Order order) {this.order = order;}@Overridepublic void execute() {order.cancel();}
}
策略模式(支付方式)
// 支付策略接口
interface PaymentStrategy {void pay(double amount);
}// 信用卡支付策略
class CreditCardPayment implements PaymentStrategy {@Overridepublic void pay(double amount) {// 信用卡支付逻辑System.out.println("Paid " + amount + " using Credit Card.");}
}// 支付宝支付策略
class AlipayPayment implements PaymentStrategy {@Overridepublic void pay(double amount) {// 支付宝支付逻辑System.out.println("Paid " + amount + " using Alipay.");}
}// 支付上下文
class PaymentContext {private PaymentStrategy strategy;public void setPaymentStrategy(PaymentStrategy strategy) {this.strategy = strategy;}public void pay(double amount) {strategy.pay(amount);}
}
观察者模式(通知用户)
// 观察者接口
interface Observer {void update(String message);
}// 用户类
class User implements Observer {private String name;public User(String name) {this.name = name;}@Overridepublic void update(String message) {System.out.println("Notify " + name + ": " + message);}
}

使用示例

public class Main {public static void main(String[] args) {// 创建用户User user = new User("Alice");// 创建商品Product product1 = new Product("Laptop", 1000);Product product2 = new Product("Phone", 500);// 创建购物车并添加商品ShoppingCart cart = new ShoppingCart();cart.addItem(product1);cart.addItem(product2);System.out.println("Total cart price: " + cart.getPrice());// 创建订单并添加观察者Order order = new Order();order.addObserver(user);// 提交订单OrderCommand submitOrder = new SubmitOrderCommand(order);submitOrder.execute();// 选择支付方式并支付PaymentContext paymentContext = new PaymentContext();paymentContext.setPaymentStrategy(new CreditCardPayment());paymentContext.pay(cart.getPrice());// 取消订单OrderCommand cancelOrder = new CancelOrderCommand(order);cancelOrder.execute();}
}

设计模式类图

组合模式(购物车设计)
contains
«interface»
ProductComponent
+double getPrice()
Product
+String name
+double price
+double getPrice()
+String getName()
ShoppingCart
+List<ProductComponent> items
+addItem(ProductComponent item)
+removeItem(ProductComponent item)
+double getPrice()
命令模式(订单处理)
uses
«interface»
OrderCommand
+void execute()
SubmitOrderCommand
-Order order
+SubmitOrderCommand(Order order)
+void execute()
CancelOrderCommand
-Order order
+CancelOrderCommand(Order order)
+void execute()
Order
+String status
+void submit()
+void cancel()
+void addObserver(Observer observer)
+void notifyObservers()
策略模式(支付方式)
«interface»
PaymentStrategy
+void pay(double amount)
CreditCardPayment
+void pay(double amount)
AlipayPayment
+void pay(double amount)
PaymentContext
-PaymentStrategy strategy
+void setPaymentStrategy(PaymentStrategy strategy)
+void pay(double amount)
观察者模式(通知用户)
«interface»
Observer
+void update(String message)
User
-String name
+User(String name)
+void update(String message)
Order
-List<Observer> observers
+void addObserver(Observer observer)
+void notifyObservers()
+void submit()
+void cancel()

整体类图

owns
contains
generates
notifies
uses
uses
User
+String name
+User(String name)
+void update(String message)
ShoppingCart
+List<ProductComponent> items
+addItem(ProductComponent item)
+removeItem(ProductComponent item)
+double getPrice()
Product
+String name
+double price
+double getPrice()
Order
+String status
+void submit()
+void cancel()
+void addObserver(Observer observer)
+void notifyObservers()
«interface»
OrderCommand
+void execute()
SubmitOrderCommand
-Order order
+SubmitOrderCommand(Order order)
+void execute()
CancelOrderCommand
-Order order
+CancelOrderCommand(Order order)
+void execute()
«interface»
PaymentStrategy
+void pay(double amount)
PaymentContext
-PaymentStrategy strategy
+void setPaymentStrategy(PaymentStrategy strategy)
+void pay(double amount)
CreditCardPayment
+void pay(double amount)
AlipayPayment
+void pay(double amount)
«interface»
Observer
+void update(String message)

总结与反思

通过本项目,我们综合应用了组合模式、命令模式、策略模式和观察者模式,解决了在线购物系统的设计需求。通过这些模式,我们实现了系统模块的解耦和灵活扩展,使得代码结构更加清晰、易于维护。

专栏推广

如果你喜欢这篇文章,请关注、收藏、点赞,并查看我的专栏“深入学习设计模式”获取更多内容。你的支持是我持续创作的动力!

推荐两个专栏:

  • 从零开始学习算法
  • 深入学习设计模式

通过这样详细的设计和实现过程,读者可以在实践中深入理解并应用设计模式。这种结构不仅能够提升文章的实用性和可读性,还能有效推广专栏内容。

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

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

相关文章

Qt中的高分辨率及缩放处理

写在前面 使用Qt开发界面客户端&#xff0c;需要考虑不同分辨率及缩放对UI界面的影响&#xff0c;否则会影响整体的交互使用。 问题 高分辨率/缩放设备上图片/图标模糊 若不考虑高分辨及缩放处理&#xff0c;在高分辨率/缩放设备上&#xff0c;软件中的图片、图标可能会出现…

【数据治理】隐私计算:数据治理中的安全守护者

隐私计算&#xff1a;数据治理中的安全守护者 引言一、隐私计算概述二、隐私计算的关键技术及其核心与业务逻辑三、隐私计算在数据治理中的应用案例四、隐私计算面临的挑战与未来发展五、结论 引言 数据治理是现代企业运营的关键组成部分&#xff0c;特别是在数据安全和隐私保…

调试DM9000过程中出现的认知与逻辑问题

在单片机项目中&#xff0c;很多难解的、涉及到硬件的bug&#xff0c;往往会采用对比实验的方式&#xff0c;即正常板子和异常板子跑同一份代码来对比现象。 这里有一个很重要的认知前提&#xff0c;就是这份代码不一定没有问题&#xff0c;只能说这份代码放在正常的硬件上没有…

解决jupyter argparse报错

jupyter argparse报错 文章目录 一、jupyter argparse报错 一、jupyter argparse报错 args parser.parse_args()这行代码改为&#xff1a; args parser.parse_args(args[])完整的代码为&#xff1a; import argparseparser argparse.ArgumentParser() parser.add_argumen…

力扣题解(零钱兑换II)

518. 零钱兑换 II 给你一个整数数组 coins 表示不同面额的硬币&#xff0c;另给一个整数 amount 表示总金额。 请你计算并返回可以凑成总金额的硬币组合数。如果任何硬币组合都无法凑出总金额&#xff0c;返回 0 。 假设每一种面额的硬币有无限个。 题目数据保证结果符合 3…

sourcetree中常用功能使用方法及gitlab冲突解决

添加至缓存&#xff1a;等于git add 提交&#xff1a;等于git commit 拉取/获取&#xff1a;等于git pull ,在每次要新增代码或者提交代码前需要先拉取一遍服务器中最新的代码&#xff0c;防止服务器有其他人更新了代码&#xff0c;但我们自己本地的代码在我们更新前跟服务器不…

Java实战中如何使用多线程(线程池)及其为什么使用?

这个话题在入行之前就想过很多次&#xff0c;很多8古文或者你搜索的结果都是告诉你什么提高高并发或者是一些很高大上的话&#xff0c;既没有案例也没有什么公式去证明&#xff0c;但是面试中总是被问到&#xff0c;也没有实战经历&#xff0c;所以面试时一问到多线程的东西就无…

JAVA零基础小白自学日志——第十九天

文章目录 1.private&#xff08;私有&#xff09;2.static&#xff08;静态&#xff09;3.final&#xff08;最终&#xff09;[1].fianl修饰变量[2].fianl修饰方法[3].fianl修饰类[4].为什么需要fianl关键字修饰类和方法 4.private\static\final的共同点5.同名变量6.方法重载和…

深度学习入门——与学习相关的技巧

前言 本章将介绍神经网络的学习中的一些重要观点&#xff0c;主题涉及寻找最优权重参数的最优化方法、权重参数的初始值、超参数的设定方法等 此外&#xff0c;为了应对过拟合&#xff0c;本章还将介绍权值衰减、Dropout等正则化方法&#xff0c;并进行实现。 最后将对近年来…

细说MCU用单路DAC模块设计和输出锯齿波的实现方法

目录 一、STM32G474RE的DAC模块 二、配置 1.配置DAC 2.选择时钟源和Debug 3.配置系统时钟 三、代码修改 1.启动DAC 2.给DAC的数据输出寄存器赋值 3.运行并观察输出 一、STM32G474RE的DAC模块 有些MCU本身就带有数/模转换器(Digital to Analog Converter,DAC)模块&am…

昇思25天学习打卡营第20天|Diffusion扩散模型

Mindspore框架利用扩散模型DDPM生成高分辨率图像&#xff08;生成高保真图像项目实践&#xff09; Mindspore框架利用扩散模型DDPM生成高分辨率图像|&#xff08;一&#xff09;关于denoising diffusion probabilistic model &#xff08;DDPM&#xff09;模型Mindspore框架利…

差分进化算法原理及其MATLAB/Python代码

1.算法简介 引用自&#xff1a;Storn R, Price K. Differential evolution–a simple and efficient heuristic for global optimization over continuous spaces[J]. Journal of global optimization, 1997, 11: 341-359. 今天给大家带来的是一个非常经典的智能优化算法–差分…

【多模态】42、LLaVA-UHD | 支持任意纵横比和大分辨率图像输入的 LLaVA

论文&#xff1a;LLaVA-UHD: an LMM Perceiving Any Aspect Ratio and High-Resolution Images 代码&#xff1a;https://github.com/thunlp/LLaVA-UHD 出处&#xff1a;清华 | 新加坡国立大学 | 中国科学院大学 一、背景 现有的很多 LMM 都是将图像处理成固定的纵横比&…

Ubuntu编译ffmpeg并添加cmake工程

文章目录 前言前提须知为什么要自己编译 FFmpeg前提软件包与工具的安装编译ffmpeg写CMakeList.txt包含ffmpeg到我们项目中 总结 前言 FFmpeg 是一个领先的多媒体框架&#xff0c;能够解码、编码、转码、复用、解复用、流化、过滤和播放几乎所有人类和机器创造的内容。FFmpeg 包…

探索Web世界:WebKit的地理位置API

探索Web世界&#xff1a;WebKit的地理位置API 在数字时代&#xff0c;地理位置信息已成为许多在线服务和应用的关键组成部分。WebKit&#xff0c;作为众多流行浏览器的内核&#xff0c;如Safari、QQ浏览器等&#xff0c;提供了强大的地理位置API&#xff08;Geolocation API&a…

设计模式11-原型模式

设计模式11-原型模式 写在前面对象创建模式典型模式原型模式动机结构代码推导应用特点要点总结 原型模式与工厂方法模式对比工厂方法模式原型模式什么时候用什么模式 写在前面 对象创建模式 通过对象创建模式绕开动态内存分配来避免创建过程中所导致的耦合过紧的问题。从而支…

数学建模--国赛备赛---TOPSIS算法

目录 1.准备部分 1.1提交材料 1.2MD5码相关要求 2.TOPSIS算法 2.1算法概述 2.2基本概念 2.3算法核心思想 2.4拓展思考 3.适用赛题 3.1适用赛题说明 3.2适用赛题举例 4.赛题分析 4.1指标的分类 4.2数据预处理 4.2.1区间型属性的变换 4.2.2向量规范化 4.3数据加…

基于 Three.js 的 3D 模型加载优化

作者&#xff1a;来自 vivo 互联网前端团队- Su Ning 作为一个3D的项目&#xff0c;从用户打开页面到最终模型的渲染需要经过多个流程&#xff0c;加载的时间也会比普通的H5项目要更长一些&#xff0c;从而造成大量的用户流失。为了提升首屏加载的转化率&#xff0c;需要尽可能…

IDEA的断点调试(Debug)

《IDEA破解、配置、使用技巧与实战教程》系列文章目录 第一章 IDEA破解与HelloWorld的实战编写 第二章 IDEA的详细设置 第三章 IDEA的工程与模块管理 第四章 IDEA的常见代码模板的使用 第五章 IDEA中常用的快捷键 第六章 IDEA的断点调试&#xff08;Debug&#xff09; 第七章 …

【内网安全】横向移动-Kerberos-SPN-WinRM-RDP

目录 环境介绍与横向移动前置域横向移动-WinRM-WinRS移动条件&#xff1a; 步骤0、攻击机开启winrm服务&#xff1a;1.CS探针5985端口&#xff1a;2.连接目标主机并执行命令&#xff1a;3.上线CS&MSF:4.CS内置横向移动-winrm 域横向移动-RDP简介与条件RDP横向移动连接的三种…