状态模式揭秘-如何优雅地处理复杂状态转换

这篇具有很好参考价值的文章主要介绍了状态模式揭秘-如何优雅地处理复杂状态转换。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

状态模式揭秘-如何优雅地处理复杂状态转换,设计模式,设计模式,状态模式,java
​🌈 个人主页:danci_
🔥 系列专栏:《设计模式》
💪🏻 制定明确可量化的目标,并且坚持默默的做事。


探索设计模式的魅力:状态模式揭秘-如何优雅地处理复杂状态转换

一、案例场景🔍

1.1 经典的运用场景

    状态模式是一种行为设计模式,它允许对象在其内部状态改变时改变它的行为。这个模式使得对象看起来好像修改了它的类。以下是几个状态模式的经典场景:

  • ✨订单处理系统: 在电商系统中,订单的状态可能会经历多个阶段,如“待支付”、“已支付”、“待发货”、“已发货”、“已完成”等。每个状态对应不同的行为,比如“待支付”状态下可以进行支付操作,“已发货”状态下可以查询物流信息等。通过状态模式,我们可以清晰地管理订单的状态转换和相关行为。
  • ✨交通信号灯控制系统: 交通信号灯有红、黄、绿三种状态,每种状态下信号灯的行为是不同的。比如红灯亮时,车辆需要停止;绿灯亮时,车辆可以通行;黄灯亮时,车辆需要准备停止。通过状态模式,我们可以方便地实现信号灯的状态转换和控制逻辑。
  • ✨用户登录状态管理: 在用户登录系统中,用户的状态可以分为“未登录”、“已登录”等。不同状态下,用户的权限和操作是不同的。比如未登录状态下,用户只能浏览部分页面;已登录状态下,用户可以访问更多功能和页面。通过状态模式,我们可以实现用户登录状态的管理和权限控制。

    下面我们来实现✨订单处理系统。

1.2 一坨坨代码实现😻

状态模式揭秘-如何优雅地处理复杂状态转换,设计模式,设计模式,状态模式,java

    使用一个简单的状态机和状态枚举来实现这个场景。下面是一个基于Java的简单实现示例:

  1. 首先,定义一个表示订单状态的枚举:
public enum OrderStatus {  
    PENDING_PAYMENT("待支付"),  
    PAYMENT_RECEIVED("已支付"),  
    SHIPPED("已发货"),  
    COMPLETED("已完成");  
  
    private final String displayName;  
  
    OrderStatus(String displayName) {  
        this.displayName = displayName;  
    }  
  
    public String getDisplayName() {  
        return displayName;  
    }  
  
    // 可以根据需要添加更多方法,比如判断是否可以转换到某个状态等  
}
  1. 接下来,我们定义一个Order类来表示订单及其状态转换的逻辑:
public class Order {  
    private OrderStatus status;  
    private String orderId;  
  
    public Order(String orderId) {  
        this.orderId = orderId;  
        this.status = OrderStatus.PENDING_PAYMENT; // 初始状态为待支付  
    }  
  
    public String getOrderId() {  
        return orderId;  
    }  
  
    public OrderStatus getStatus() {  
        return status;  
    }  
  
    // 状态转换方法  
    public void pay() {  
        if (status == OrderStatus.PENDING_PAYMENT) {  
            status = OrderStatus.PAYMENT_RECEIVED;  
            System.out.println("Order " + orderId + " status changed to: " + status.getDisplayName());  
        } else {  
            System.out.println("Cannot pay for order " + orderId + " in its current state.");  
        }  
    }  
  
    public void ship() {  
        if (status == OrderStatus.PAYMENT_RECEIVED) {  
            status = OrderStatus.SHIPPED;  
            System.out.println("Order " + orderId + " status changed to: " + status.getDisplayName());  
        } else {  
            System.out.println("Cannot ship order " + orderId + " in its current state.");  
        }  
    }  
  
    public void complete() {  
        if (status == OrderStatus.SHIPPED) {  
            status = OrderStatus.COMPLETED;  
            System.out.println("Order " + orderId + " status changed to: " + status.getDisplayName());  
        } else {  
            System.out.println("Cannot complete order " + orderId + " in its current state.");  
        }  
    }  
  
    // 可以根据需要添加更多方法和逻辑  
}
  1. 现在,你可以通过创建一个Order对象并调用其状态转换方法来模拟订单的状态变化:
public class OrderProcessingDemo {  
    public static void main(String[] args) {  
        Order order = new Order("12345");  
        System.out.println("Current order status: " + order.getStatus().getDisplayName());  
  
        order.pay();  
        System.out.println("Current order status: " + order.getStatus().getDisplayName());  
  
        order.ship();  
        System.out.println("Current order status: " + order.getStatus().getDisplayName());  
  
        order.complete();  
        System.out.println("Current order status: " + order.getStatus().getDisplayName());  
  
        // 尝试在非法状态下进行状态转换  
        order.pay(); // 应该不会成功,因为订单已经完成  
    }  
}

    在这个实现中,我们直接在Order类中处理了状态转换的逻辑。每个状态转换方法(pay、ship、complete)都会检查当前状态是否允许进行转换,并相应地更新状态或打印错误消息。虽然这个实现很简单,但它缺乏一些设计模式所提供的灵活性和可扩展性。在实际项目中,你可能会考虑使用状态模式、策略模式或模板方法模式等来实现更复杂的状态管理逻辑。然而,根据题目的要求,这里提供了一个不使用设计模式的简单实现。

1.3 痛点

状态模式揭秘-如何优雅地处理复杂状态转换,设计模式,设计模式,状态模式,java
    上述实现确实存在一些缺点,下面逐一分析:

  1. 硬编码的状态转换逻辑:
    在上述实现中,状态转换的逻辑是直接硬编码在Order类中的pay、ship和complete方法里。这意味着如果未来需要添加新的状态或更改现有的状态转换逻辑,我们必须修改Order类的源代码。这违反了开闭原则(Open-Closed Principle),即软件实体应该对扩展开放,对修改关闭。
  2. 缺乏灵活性:
    由于状态转换逻辑是固定的,系统无法轻松适应新的业务规则或变化。例如,如果引入了一个新的状态“部分发货”,或者某些状态下允许退款操作,现有的代码结构将难以应对这些变化。
  3. 状态和行为紧密耦合:
    在上述实现中,状态和与状态相关的行为(即状态转换)是紧密耦合的。这导致了高内聚低耦合的设计原则的违反。理想情况下,状态应该只表示数据,而行为应该由独立的组件(如状态机)来管理。
  4. 可维护性问题:
    随着业务逻辑的增长和复杂性的增加,直接在Order类中管理状态转换将变得越来越困难。代码将变得难以理解和维护,特别是当多个开发人员参与项目时。
  5. 错误处理不足:
    在当前实现中,错误处理仅限于打印错误消息到控制台。在实际的生产环境中,通常需要更复杂的错误处理机制,如回滚操作、日志记录、通知用户或管理员等。
  6. 可扩展性问题:
    由于状态转换逻辑直接嵌入在Order类中,因此添加新的状态或转换逻辑需要修改现有的类结构。这可能会引入新的错误并破坏现有功能的稳定性。此外,每次添加新功能时都需要重新测试和验证整个系统。

二、解决方案

状态模式揭秘-如何优雅地处理复杂状态转换,设计模式,设计模式,状态模式,java
    使用状态模式可以有效地解决上述提到的一些缺点。状态模式允许一个对象在其内部状态改变时改变它的行为,使得对象看起来好像修改了它的类。在状态模式中,我们定义状态和状态之间的转换,将状态转换的逻辑封装在状态对象自身中,而不是将其分散在多个条件语句中。

2.1 定义

状态模式(State Pattern)是一种行为设计模式,它允许一个对象在其内部状态改变时改变它的行为。状态模式把与特定状态相关的行为封装到一个个的类中,当对象的状态改变时,它的行为也会随着改变。

2.2 案例分析🧐

状态模式揭秘-如何优雅地处理复杂状态转换,设计模式,设计模式,状态模式,java

2.3 状态模式结构图及说明

状态模式揭秘-如何优雅地处理复杂状态转换,设计模式,设计模式,状态模式,java
主要组件:

  1. Context(上下文):它定义了客户感兴趣的接口,并且维护一个具体状态对象的实例,这个具体状态对象定义了当前状态。
  2. State(抽象状态):这是一个抽象类,它定义了状态转换的接口,这个接口由具体状态类实现。
  3. ConcreteState(具体状态):具体状态类实现了抽象状态定义的接口,从而实现状态转换和具体行为。

说明:

  1. 封装了状态的转换逻辑:状态模式将状态转换逻辑封装在状态类中,而不是散布在多个条件语句中。这有助于减少代码的复杂性,并使状态转换逻辑更易于理解和维护。
  2. 增加新的状态或行为变得更容易:由于状态和行为都被封装在单独的类中,因此添加新的状态或行为只需要添加新的状态类,而不需要修改其他代码。这符合开闭原则,即对扩展开放,对修改封闭。
  3. 状态转换的显式化:状态模式使得状态转换变得显式化,因为状态的转换是通过调用状态对象的方法来实现的,而不是通过修改上下文的状态变量来实现的。这使得状态转换更加清晰和可预测。
  4. 过多的状态类可能导致类爆炸:如果一个对象有很多状态,并且每个状态的行为差异很大,那么可能需要为每个状态创建一个单独的类。这可能会导致类数量过多,增加系统的复杂性。

2.4 使用状态模式重构示例

    使用状态模式来实现上述场景时,首先需要定义状态接口和具体的状态类,然后在上下文类(如Order)中维护一个对当前状态的引用。状态类将封装与特定状态相关的行为,包括状态转换。
    下面是一个使用状态模式实现的订单处理系统的示例:

  1. 状态接口
public interface OrderState {  
    void pay(Order order);  
    void ship(Order order);  
    void complete(Order order);  
    // 可能还需要其他方法,如退款、部分发货等  
} 
  1. 具体的状态类
public class CreatedState implements OrderState {  
    @Override  
    public void pay(Order order) {  
        // 处理支付逻辑  
        System.out.println("Order paid.");  
        order.setState(new PaidState());  
    }  
  
    @Override  
    public void ship(Order order) {  
        System.out.println("Cannot ship order in Created state.");  
    }  
  
    @Override  
    public void complete(Order order) {  
        System.out.println("Cannot complete order in Created state.");  
    }  
}
public class PaidState implements OrderState {  
    @Override  
    public void pay(Order order) {  
        System.out.println("Order already paid.");  
    }  
  
    @Override  
    public void ship(Order order) {  
        // 处理发货逻辑  
        System.out.println("Order shipped.");  
        order.setState(new ShippedState());  
    }  
  
    @Override  
    public void complete(Order order) {  
        System.out.println("Cannot complete order before it is shipped.");  
    }  
}  
  
public class ShippedState implements OrderState {  
    @Override  
    public void pay(Order order) {  
        System.out.println("Order already paid and shipped.");  
    }  
  
    @Override  
    public void ship(Order order) {  
        System.out.println("Order already shipped.");  
    }  
  
    @Override  
    public void complete(Order order) {  
        // 处理完成订单逻辑  
        System.out.println("Order completed.");  
        order.setState(new CompletedState());  
    }  
}  
  
public class CompletedState implements OrderState {  
    @Override  
    public void pay(Order order) {  
        System.out.println("Cannot pay for a completed order.");  
    }  
  
    @Override  
    public void ship(Order order) {  
        System.out.println("Cannot ship a completed order.");  
    }  
  
    @Override  
    public void complete(Order order) {  
        System.out.println("Order already completed.");  
    }  
}  
  1. 上下文类
public class Order {  
    private OrderState state;  
  
    public Order() {  
        this.state = new CreatedState(); // 初始状态  
    }  
  
    public void setState(OrderState state) {  
        this.state = state;  
    }  
  
    public void pay() {  
        state.pay(this);  
    }  
  
    public void ship() {  
        state.ship(this);  
    }  
  
    public void complete() {  
        state.complete(this);  
    }  
  
    // 可能还有其他与订单相关的方法和属性  
}  
  1. 使用示例
public class StatePatternDemo {  
    public static void main(String[] args) {  
        Order order = new Order();  
  
        order.pay(); // 当前状态为CreatedState,调用pay会转移到PaidState  
        order.ship(); // 当前状态为PaidState,调用ship会转移到ShippedState  
        order.complete(); // 当前状态为ShippedState,调用complete会转移到CompletedState  
  
        order.pay(); // 当前状态为CompletedState,不能再支付  
        order.ship(); // 当前状态为CompletedState,不能再发货  
        order.complete(); // 当前状态为CompletedState,订单已完成  
    }  
}

    在这个示例中,Order类代表上下文,它有一个state字段来保存当前状态,并且提供了pay、ship和complete等方法来触发状态转换。每个具体的状态类(如CreatedState、PaidState等)都实现了OrderState接口,并定义了在当前状态下这些方法的行为。
    注:这只是一个简单的示例,实际应用中可能还需要处理更多的状态和行为,并且状态转换的逻辑可能会更加复杂。此外,为了提高代码的可维护性和可读性,还可以考虑使用枚举类型来定义状态,或者使用状态机框架来管理状态转换。

2.5 重构后解决的问题

状态模式揭秘-如何优雅地处理复杂状态转换,设计模式,设计模式,状态模式,java
    使用状态模式可以有效地解决 1.3 痛点 中提到的一些缺点。状态模式允许一个对象在其内部状态改变时改变它的行为,使得对象看起来好像修改了它的类。在状态模式中,我们定义状态和状态之间的转换,将状态转换的逻辑封装在状态对象自身中,而不是将其分散在多个条件语句中。
    以下是状态模式如何解决上述缺点的原因:

  1. 解耦状态和行为:
    在状态模式中,状态和行为被封装在单独的状态类中。这意味着Order类不再需要直接处理状态转换的逻辑。每个状态类负责定义在当前状态下允许的行为以及状态转换的规则。这大大减少了Order类的复杂性,并且使得状态和行为之间的关系更加清晰和易于管理。
  2. 提高灵活性和可扩展性:
    由于状态转换逻辑被封装在状态类中,添加新的状态或更改现有状态的行为变得相对容易。我们只需要定义新的状态类并实现相应的行为即可,而不需要修改使用状态模式的上下文类(在本例中是Order类)。这符合开闭原则,即软件实体应该对扩展开放,对修改关闭。
  3. 更好的错误处理:
    在状态模式中,状态类可以定义自己的错误处理逻辑。例如,如果尝试在不合适的状态下执行某个操作,状态类可以抛出异常或返回错误码,而不是在上下文类中打印错误消息。这提供了更好的错误处理机制,并使得错误处理更加集中和一致。
  4. 提高可维护性:
    将状态和行为封装在单独的状态类中使得代码更加模块化和可维护。每个状态类只关注自己的行为和转换规则,这使得代码更加清晰、易于理解和测试。此外,由于状态类之间是松耦合的,因此可以独立地修改和测试它们,而不会影响到其他状态类或使用它们的上下文类。
  5. 支持复杂的业务逻辑:
    状态模式能够轻松地支持复杂的业务逻辑和状态转换规则。通过定义更多的状态类和转换逻辑,我们可以实现更加精细和灵活的状态管理。此外,状态模式还可以与其他设计模式(如策略模式、观察者模式等)结合使用,以构建更加复杂和强大的软件系统。

    通过使用状态模式可以解决硬编码的状态转换逻辑、缺乏灵活性、状态和行为紧密耦合、可维护性问题以及错误处理不足等缺点。通过将状态和行为封装在单独的状态类中,我们实现了状态与行为的解耦,提高了系统的灵活性、可扩展性和可维护性。


转载文章只截取部分内容
详请跳转原文:https://blog.csdn.net/danci_/article/details/136367657文章来源地址https://www.toymoban.com/news/detail-839987.html


到了这里,关于状态模式揭秘-如何优雅地处理复杂状态转换的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • JavaScript责任链模式:如何优雅地处理请求

    在实际开发中,我们经常会遇到需要处理一系列请求的情况,而这些请求可能需要被不同的处理器处理。这时候,责任链模式就可以派上用场了。本文将介绍JavaScript中的责任链模式,并通过一个实际的例子来说明如何使用责任链模式来优雅地处理请求。 责任链模式是一种行

    2024年02月11日
    浏览(32)
  • 【设计模式】SpringBoot优雅使用策略模式

    本篇文章主要会描述SpringBoot与策略模式的结合使用,因为不涉及到理论部分,所以在阅读本篇之前,需要对策略模式的理论已经有了一个基本的了解。 策略模式有3种角色,分别为: 选择器 、 抽象策略 、 策略实例 。 其中 选择器 selector 又被称为上下文 context ,其作用为通

    2024年02月10日
    浏览(30)
  • 【设计模式】六、【创建性模式】揭秘单例模式:从生活例子到Java代码

    转自:提升工作效率-单例模式详解 1、介绍 单例模式的产生,它主要是为了解决在软件系统中,对于一些类,我们只需要创建一个全局唯一的实例。例如,系统的配置信息、数据库连接池等。如果有多个实例可能会导致状态不一致,或者额外的资源消耗。这个需求在很多软件

    2024年02月06日
    浏览(32)
  • 掌握设计模式:深入了解命令模式的优雅调度与行为解耦

    命令模式是一种行为设计模式,其目的是将请求发送者和接收者解耦,从而允许发送者发送请求,而无需知道请求的具体处理方式。在命令模式中,请求被封装为一个对象,这个对象包含了执行请求所需的所有信息,包括调用方法、参数等。这样,请求的发送者只需知道如何

    2024年01月25日
    浏览(41)
  • Python设计模式:你的代码真的够优雅吗?

    当涉及到代码优化时,Python作为一种高级编程语言,具有广泛的应用领域和强大的功能。在软件开发中,设计模式是一种被广泛采用的解决问题的方案,它提供了一种在特定情境中重复使用的可行方案。在Python中,有许多设计模式可以用来优化代码。 其中两种常见的设计模式

    2024年01月25日
    浏览(34)
  • 探索设计模式的魅力:揭秘B/S模式在AI大模型时代的蜕变与进化

    ​🌈 个人主页: danci_ 🔥 系列专栏: 《设计模式》 💪🏻 制定明确可量化的目标,坚持默默的做事。 揭秘B/S模式在AI大模型时代的蜕变与进化     🚀在AI的波澜壮阔中,B/S模式(浏览器/服务器模式)正静悄悄地发生着翻天覆地的变化。🌟 当AI大模型如同潮水般涌现,这

    2024年04月08日
    浏览(36)
  • 使用 Goroutine 和 Channel 来实现更复杂的并发模式,如并发任务执行、并发数据处理,如何做?

    使用 Goroutine 和 Channel 来实现更复杂的并发模式是 Go 语言的强大特性之一。 下面分别介绍如何实现并发任务执行和并发数据处理: 并发任务执行: 假设您有一些任务需要并发地执行,您可以使用 Goroutine 来同时执行这些任务,然后使用 Channel 来汇总结果。 下面是一个示例,

    2024年01月22日
    浏览(34)
  • 【设计模式】订单状态流传中的状态机与状态模式

    状态模式一般是用在对象内部的 状态流转 场景中,用来实现 状态机 。 什么是状态机呢? 状态机是对状态转移的抽象,由 事件 、 状态 、 动作 组成,事件有时候也被称为 转移事件 或者 转移 ,当事件触发时,可以将状态由一个状态变更为另一个状态,并执行动作。其中,

    2024年02月12日
    浏览(31)
  • 探索设计模式的魅力:迭代器模式让你轻松驾驭复杂数据集合

    ​🌈 个人主页: danci_ 🔥 系列专栏: 《设计模式》 💪🏻 制定明确可量化的目标,并且坚持默默的做事。 🚀 定义迭代器模式 用来提供一种方法顺序访问一个集合对象中的各个元素,而不需要暴露该对象的内部表示。 就像一个迷宫探险家,在复杂的迷宫通道中逐一探索,

    2024年02月22日
    浏览(33)
  • 小程序设计模式之状态模式实践-蓝牙配网_小程序 蓝牙状态模式

    */ disconnect() {} /** * 蓝牙连接成功 * @see UnConnectState */ connectSuccess() {} /** * 蓝牙连接失败 * @see UnConnectState */ connectFail() {} /** * 路由数据接收完成 * @see ReceivedState */ received() {} /** * 认证中 * @see AuthenticatingState */ authenticating() {} /** * 认证完成 * @see AuthenticatedState */ authenticated() {} /*

    2024年04月14日
    浏览(26)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包