Java设计模式之状态模式架构高扩展的订单状态管理

news2024/12/26 22:04:05

🧑 博主简介:CSDN博客专家历代文学网(PC端可以访问:https://literature.sinhy.com/#/literature?__c=1000,移动端可微信小程序搜索“历代文学”)总架构师,15年工作经验,精通Java编程高并发设计Springboot和微服务,熟悉LinuxESXI虚拟化以及云原生Docker和K8s,热衷于探索科技的边界,并将理论知识转化为实际应用。保持对新技术的好奇心,乐于分享所学,希望通过我的实践经历和见解,启发他人的创新思维。在这里,我希望能与志同道合的朋友交流探讨,共同进步,一起在技术的世界里不断学习成长。
技术合作请加本人wx(注明来自csdn):foreast_sea

在这里插入图片描述


在这里插入图片描述

Java设计模式之状态模式架构高扩展的订单状态管理

一、引言

在当今电商蓬勃发展的时代,订单管理系统是电商平台的核心组件之一。一个订单从产生到最终完成或关闭,会经历多个不同的状态,如“已下单”“已付款”“已发货”“已收货”“已退款”等。随着电商业务的日益复杂,订单状态的管理也变得越发棘手。

传统的订单状态管理方式往往是使用大量的 if-else 语句来判断订单的当前状态,并执行相应的操作。例如:

if (order.getStatus().equals("已付款")) {
    // 通知仓库发货
    warehouseService.notifyShipment(order);
} else if (order.getStatus().equals("已收货")) {
    // 触发评价流程
    reviewService.startReview(order);
}

这种方式在订单状态较少且业务逻辑简单时,或许还能应付。然而,随着电商业务的不断拓展,新的订单状态可能会被引入,业务规则也会不断变化。这时,if-else 代码块会变得越来越臃肿,难以维护和扩展。一旦修改某个状态的业务逻辑,可能会牵一发而动全身,引入新的错误。

而且,这种硬编码的方式使得代码的可读性较差,新加入的开发人员可能需要花费大量时间来理解整个订单状态管理的逻辑。此外,从性能角度来看,大量的 if-else 语句可能会影响系统的响应速度,尤其是在高并发的订单处理场景下。

为了解决这些问题,我们可以引入设计模式中的状态模式。状态模式允许一个对象在其内部状态改变时改变它的行为。通过将每个订单状态封装成一个独立的类,每个类负责处理该状态下的特定行为,这样可以使订单状态管理的代码更加清晰、可维护和可扩展,同时也有助于提升系统的性能和可读性等非功能性指标。接下来,我们将深入探讨如何使用状态模式来实现电商订单状态管理。

二、状态模式概述

状态模式属于行为型设计模式。它的核心思想是将对象的行为封装在不同的状态类中,当对象的内部状态发生改变时,其行为也会随之改变,而这种改变对于外部使用者来说是透明的。

在状态模式中,主要涉及以下几个角色:

  • 上下文(Context):它是持有状态的对象,通常会定义一个抽象的状态接口,并维护一个当前状态的引用。上下文对象将具体的状态处理委托给当前状态对象。例如在订单管理中,订单对象就是上下文,它包含了订单的基本信息以及当前的订单状态。
  • 抽象状态(State):定义了一个接口,用于封装与特定状态相关的行为。在订单状态管理中,这可以是一个名为OrderState的抽象类或接口,它声明了如handle等方法,不同的具体订单状态类将实现这些方法。
  • 具体状态(Concrete State):实现抽象状态接口,针对不同的状态提供具体的行为实现。比如PaidOrderState(已付款状态)类实现OrderState接口,并实现handle方法来处理已付款状态下的业务逻辑,如通知仓库发货。

三、使用状态模式实现订单状态管理的步骤

(一)定义抽象状态接口

首先,我们定义一个抽象的订单状态接口OrderState,它包含了处理订单状态相关操作的方法。

// 订单状态接口
public interface OrderState {
    // 处理订单状态改变时的操作
    void handle(Order order);
}

(二)创建具体订单状态类

接下来,针对每个订单状态创建具体的状态类,并实现OrderState接口。

  1. 已下单状态类
// 已下单状态类
public class PlacedOrderState implements OrderState {
    @Override
    public void handle(Order order) {
        System.out.println("订单已下单,等待付款。");
        // 可以在此处添加一些针对已下单状态的业务逻辑,如预留库存等
    }
}
  1. 已付款状态类
// 已付款状态类
import warehouse.WarehouseService;

public class PaidOrderState implements OrderState {
    private WarehouseService warehouseService;

    public PaidOrderState(WarehouseService warehouseService) {
        this.warehouseService = warehouseService;
    }

    @Override
    public void handle(Order order) {
        System.out.println("订单已付款,通知仓库发货。");
        // 调用仓库服务的发货通知方法
        warehouseService.notifyShipment(order);
    }
}
  1. 已发货状态类
// 已发货状态类
public class ShippedOrderState implements OrderState {
    @Override
    public void handle(Order order) {
        System.out.println("订单已发货,等待收货。");
        // 可以在此处添加一些物流跟踪相关的业务逻辑
    }
}
  1. 已收货状态类
// 已收货状态类
import review.ReviewService;

public class ReceivedOrderState implements OrderState {
    private ReviewService reviewService;

    public ReceivedOrderState(ReviewService reviewService) {
        this.reviewService = reviewService;
    }

    @Override
    public void handle(Order order) {
        System.out.println("订单已收货,触发评价流程。");
        // 调用评价服务的开始评价方法
        reviewService.startReview(order);
    }
}
  1. 已退款状态类
// 已退款状态类
public class RefundedOrderState implements OrderState {
    @Override
    public void handle(Order order) {
        System.out.println("订单已退款,处理退款相关业务。");
        // 例如更新财务数据,释放库存等
    }
}

(三)订单类(上下文类)的设计

订单类Order作为上下文类,需要维护当前的订单状态,并提供改变状态的方法。

import java.util.Date;

// 订单类
public class Order {
    private String orderId;
    private Date orderDate;
    private double totalAmount;
    // 当前订单状态
    private OrderState currentState;

    public Order(String orderId, Date orderDate, double totalAmount) {
        this.orderId = orderId;
        this.orderDate = orderDate;
        this.totalAmount = totalAmount;
        // 初始状态为已下单
        this.currentState = new PlacedOrderState();
    }

    // 获取订单状态
    public OrderState getCurrentState() {
        return currentState;
    }

    // 设置订单状态
    public void setCurrentState(OrderState currentState) {
        this.currentState = currentState;
    }

    // 处理订单状态改变
    public void process() {
        currentState.handle(this);
    }
}

(四)模拟订单状态的切换

我们可以编写一个测试类来模拟订单状态的切换过程。

import java.util.Date;

public class OrderStatePatternTest {
    public static void main(String[] args) {
        // 创建订单
        Order order = new Order("123456", new Date(), 100.0);

        // 模拟付款操作,切换到已付款状态
        WarehouseService warehouseService = new WarehouseService();
        order.setCurrentState(new PaidOrderState(warehouseService));
        order.process();

        // 模拟发货操作,切换到已发货状态
        order.setCurrentState(new ShippedOrderState());
        order.process();

        // 模拟收货操作,切换到已收货状态
        ReviewService reviewService = new ReviewService();
        order.setCurrentState(new ReceivedOrderState(reviewService));
        order.process();

        // 模拟退款操作,切换到已退款状态
        order.setCurrentState(new RefundedOrderState());
        order.process();
    }
}

在上述测试类中,我们首先创建了一个订单,然后按照订单的实际业务流程,依次模拟了付款、发货、收货和退款操作,每次操作都通过setCurrentState方法改变订单的当前状态,并调用process方法来处理该状态下的业务逻辑。

四、状态模式在订单状态管理中的优势

(一)提高代码的可维护性

使用状态模式后,每个订单状态的业务逻辑都被封装在独立的状态类中。如果某个状态的业务逻辑发生变化,只需要修改对应的状态类即可,而不会影响到其他状态类和订单类的整体结构。例如,如果“已付款”状态下的发货通知逻辑需要修改,只需要在PaidOrderState类中进行调整,而不需要在包含大量 if-else 语句的订单处理代码中进行查找和修改。

(二)增强代码的可扩展性

当电商平台引入新的订单状态时,只需要创建一个新的具体状态类并实现OrderState接口,然后在订单类中添加相应的状态切换逻辑即可。例如,如果新增了“已换货”状态,我们可以创建ExchangedOrderState类,并在订单类中根据业务需求确定何时切换到该状态。这种扩展方式相比于在原有 if-else 代码中添加新的分支,更加清晰和易于管理。

(三)提升代码的可读性

状态模式使得订单状态管理的代码结构更加清晰。通过查看订单类和各个状态类的定义,开发人员可以很容易地理解订单在不同状态下的行为。每个状态类的名称直观地反映了该状态下的主要业务操作,如PaidOrderState表示已付款状态,其handle方法的逻辑就是处理已付款后的操作,这比在复杂的 if-else 语句中理解订单状态逻辑要容易得多。

(四)改善系统性能

在传统的 if-else 实现中,每次处理订单状态时都需要遍历所有的条件判断语句,即使订单状态已经确定。而在状态模式下,一旦订单状态确定,就直接调用对应的状态类方法,避免了不必要的条件判断,从而提高了系统的响应速度,尤其是在高并发的订单处理场景下,这种性能提升更为明显。

五、总结

在电商订单状态管理中,状态模式展现出了强大的优势。通过将订单状态的行为封装在独立的类中,提高了代码的可维护性、可扩展性、可读性,并在一定程度上改善了系统性能。在实际的电商项目开发中,合理运用状态模式能够有效地应对订单状态管理的复杂性,为系统的长期稳定运行和业务的不断拓展奠定坚实的基础。

六、参考资料文献

  • 《设计模式:可复用面向对象软件的基础》 - Erich Gamma 等著
  • Java 官方文档:https://docs.oracle.com/en/java/

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

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

相关文章

【排序用法】.NET开源 ORM 框架 SqlSugar 系列

💥 .NET开源 ORM 框架 SqlSugar 系列 🎉🎉🎉 【开篇】.NET开源 ORM 框架 SqlSugar 系列【入门必看】.NET开源 ORM 框架 SqlSugar 系列【实体配置】.NET开源 ORM 框架 SqlSugar 系列【Db First】.NET开源 ORM 框架 SqlSugar 系列…

家政小程序开发,打造便捷家政生活小程序

目前,随着社会人就老龄化和生活压力的加重,家政服务市场的需求正在不断上升,家政市场的规模也正在逐渐扩大,发展前景可观。 在市场快速发展的影响下,越来越多的企业开始进入到市场中,同时家政市场布局也发…

自然语言处理:基于BERT预训练模型的中文命名实体识别(使用PyTorch)

命名实体识别(NER) 命名实体识别(Named Entity Recognition, NER)是自然语言处理(NLP)中的一个关键任务,其目标是从文本中识别出具有特定意义的实体,并将其分类到预定义的类别中。这…

掌握 Spring Boot 中的缓存:技术和最佳实践

缓存是一种用于将经常访问的数据临时存储在更快的存储层(通常在内存中)中的技术,以便可以更快地满足未来对该数据的请求,从而提高应用程序的性能和效率。在 Spring Boot 中,缓存是一种简单而强大的方法,可以…

Unity 模拟百度地图,使用鼠标控制图片在固定区域内放大、缩小、鼠标左键拖拽移动图片

效果展示: 步骤流程: 1.使用的是UGUI,将下面的脚本拖拽到图片上即可。 using UnityEngine; using UnityEngine.UI; using UnityEngine.EventSystems;public class CheckImage : MonoBehaviour, IDragHandler, IBeginDragHandler, IEndDragH…

基础入门-Web应用OSS存储负载均衡CDN加速反向代理WAF防护部署影响

知识点: 1、基础入门-Web应用-防护产品-WAF保护 2、基础入门-Web应用-加速服务-CDN节点 3、基础入门-Web应用-文件托管-OSS存储 4、基础入门-Web应用-通讯服务-反向代理 5、基础入门-Web应用-运维安全-负载均衡 一、演示案例-Web-拓展架构-WAF保护-拦截攻击 原理&a…

指针(上)

目录 内存和地址 指针变量和地址 取地址(&) 解引用(*) 大小 类型 意义 const修饰 修饰变量 修饰指针 指针运算 指针- 整数 指针-指针 指针的关系运算 野指针 概念 成因 避免 assert断言 指针的使用 strl…

警惕开源信息成为泄密源头

文章目录 前言一、信息公开需谨慎1、警惕采购招标泄密。2、警惕信息公开泄密。3、警惕社交媒体泄密。 二、泄密风险需严防1、健全制度,明确责任。2、加强管控,严格审查。3、提高意识,谨言慎行。 前言 大数据时代,信息在网络空间发…

LearnOpenGL学习(光照 -- 颜色,基础光照,材质,光照贴图)

光照 glm::vec3 lightColor(0.0f, 1.0f, 0.0f); glm::vec3 toyColor(1.0f, 0.5f, 0.31f); glm::vec3 result lightColor * toyColor; // (0.0f, 0.5f, 0.0f); 说明:当我们把光源的颜色与物体的颜色值相乘,所得到的就是这个物体所反射的颜色。 创建…

面向对象(二)——类和对象(上)

1 类的定义 做了关于对象的很多介绍,终于进入代码编写阶段。 本节中重点介绍类和对象的基本定义,属性和方法的基本使用方式。 【示例】类的定义方式 // 每一个源文件必须有且只有一个public class,并且类名和文件名保持一致! …

3GPP R18 LTM(L1/L2 Triggered Mobility)是什么鬼?(三) RACH-less LTM cell switch

这篇看下RACH-less LTM cell switch。 相比于RACH-based LTM,RACH-less LTM在进行LTM cell switch之前就要先知道target cell的TA信息,进而才能进行RACH-less过程,这里一般可以通过UE自行测量或者通过RA过程获取,而这里的RA一般是通过PDCCH order过程触发。根据38.300中的描…

实验13 使用预训练resnet18实现CIFAR-10分类

1.数据预处理 首先利用函数transforms.Compose定义了一个预处理函数transform,里面定义了两种操作,一个是将图像转换为Tensor,一个是对图像进行标准化。然后利用函数torchvision.datasets.CIFAR10下载数据集,这个函数有四个常见的…

P1226 快速幂

【STUACM-算法入门-快速幂】https://www.bilibili.com/video/BV1Hi4y1L7qB?p2&vd_sourcee583d26dc0028b3e6ea220aadf5bc7fe 想先把a的b次方算出来再对p取模是不可能的,因为肯定超出long long 范围。 需要知道:(x*y)mod p (x mod p)*(y mod p) mo…

【力扣热题100】—— Day3.反转链表

你不会永远顺遂,更不会一直年轻,你太安静了,是时候出发了 —— 24.12.2 206. 反转链表 给你单链表的头节点 head ,请你反转链表,并返回反转后的链表。 示例 1: 输入:head [1,2,3,4,5] 输出&…

containerd安装

containerd安装 参考资料前置准备Installing containerdInstalling runcInstalling CNI plugins containerd is available as a daemon for Linux and Windows. It manages the complete container lifecycle of its host system, from image transfer and storage to containe…

底部导航栏新增功能按键

场景需求: 在底部导航栏添加power案件,单击息屏,长按 关机 如下实现图 借此需求,需要掌握技能: 底部导航栏如何实现新增、修改、删除底部导航栏流程对底部导航栏部分样式如何修改。 比如放不下、顺序排列、坑点如…

Python 入门教程(2)搭建环境 | 2.4、VSCode配置Node.js运行环境

文章目录 一、VSCode配置Node.js运行环境1、软件安装2、安装Node.js插件3、配置VSCode4、创建并运行Node.js文件5、调试Node.js代码 一、VSCode配置Node.js运行环境 1、软件安装 安装下面的软件: 安装Node.js:Node.js官网 下载Node.js安装包。建议选择L…

火语言RPA流程组件介绍--键盘按键

🚩【组件功能】:模拟键盘按键 配置预览 配置说明 按键 点击后,在弹出的软键盘上选择需要的按键 执行后等待时间(ms) 默认值300,执行该组件后等待300毫秒后执行下一个组件. 输入输出 输入类型 万能对象类型(System.Object)输出类型 万能对象类型…

【人工智能-基础】SVM中的核函数到底是什么

文章目录 支持向量机(SVM)中的核函数详解1. 什么是核函数?核函数的作用:2. 核技巧:从低维到高维的映射3. 常见的核函数类型3.1 线性核函数3.2 多项式核函数3.3 高斯径向基函数(RBF核)4. 总结支持向量机(SVM)中的核函数详解 支持向量机(SVM,Support Vector Machine)…

万字长文解读深度学习——多模态模型BLIP2

🌺历史文章列表🌺 深度学习——优化算法、激活函数、归一化、正则化 深度学习——权重初始化、评估指标、梯度消失和梯度爆炸 深度学习——前向传播与反向传播、神经网络(前馈神经网络与反馈神经网络)、常见算法概要汇总 万字长…