深究设计模式之-状态模式

状态模式(State Pattern)是一种行为型设计模式,其主要目的是允许一个对象在其内部状态改变时改变其行为,看起来就像是改变了对象的类。状态模式将对象的状态封装成独立的类,使得对象状态的变化可以独立于对象本身的变化。

状态模式的重点是在其内部可以自动切换到需要的状态对象,新的状态对象拥有新的行为,比如一个自动售货机,它可以处于三种状态:正常运行缺货维护中。在正常运行状态下,它可以接受货币并提供商品;在缺货状态下,它不接受货币并显示"抱歉,商品已售罄";在维护中状态下,它完全关闭,不接受货币也不提供商品。
这里,自动售货机的行为取决于它的状态。状态模式允许售货机在不同的状态下有不同的行为,而且状态可以在运行时动态改变,比如当库存耗尽时,自动售货机的状态会从正常运行变为缺货状态。这样,状态模式使得系统能够更加灵活地应对不同的情况,同时也使得代码更加清晰易懂。

主要角色:

  1. 上下文(Context): 定义了客户端感兴趣的接口,并且维护一个具体状态的实例,可以根据当前状态调用不同的具体状态。

  2. 状态(State): 定义了一个接口,封装了与上下文的一个特定状态相关的行为。

  3. 具体状态(Concrete State): 实现了状态接口,包含了与特定状态相关的行为。

示例:

下面是一个简单的 Java 代码示例,实现了自动售货机的状态模式:

java 复制代码
package com.luke.designpatterns.statePattern;

// 状态接口
interface VendingMachineState {
    void pay();
    void getProduct();
}

// 具体状态类 - 正常运行状态
class NormalState implements VendingMachineState {
    @Override
    public void pay() {
        System.out.println("扫码购买产品!");
    }

    @Override
    public void getProduct() {
        System.out.println("购买成功!");
    }
}

// 具体状态类 - 缺货状态
class SoldOutState implements VendingMachineState {
    @Override
    public void pay() {
        System.out.println("抱歉,商品已售罄,扫码失败");
    }

    @Override
    public void getProduct() {
        System.out.println("抱歉,商品已售罄");
    }
}

// 具体状态类 - 维护中状态
class MaintenanceState implements VendingMachineState {
    @Override
    public void pay() {
        System.out.println("机器正在维护,无法扫码支付");
    }

    @Override
    public void getProduct() {
        System.out.println("机器正在维护");
    }
}

// 环境类 - 自动售货机
class VendingMachine {
    private VendingMachineState currentState;

    public VendingMachine() {
        // 初始状态为正常运行状态
        currentState = new NormalState();
    }

    public void setState(VendingMachineState newState) {
        this.currentState = newState;
    }

    public void insertCoin() {
        currentState.pay();
    }

    public void dispenseItem() {
        currentState.getProduct();
    }
}

// 客户端代码
public class StatePatternExample {
    public static void main(String[] args) {
        VendingMachine vendingMachine = new VendingMachine();

        vendingMachine.insertCoin();
        vendingMachine.dispenseItem();

        // 模拟缺货情况
        vendingMachine.setState(new SoldOutState());
        vendingMachine.insertCoin();
        vendingMachine.dispenseItem();

        // 模拟维护中情况
        vendingMachine.setState(new MaintenanceState());
        vendingMachine.insertCoin();
        vendingMachine.dispenseItem();
    }
}

在这个例子中,VendingMachine 类是环境类,负责维护当前的状态,并根据当前状态调用相应的方法。不同的状态由实现了 VendingMachineState 接口的具体状态类来表示,每个具体状态类实现了在特定状态下的行为。客户端代码可以通过调用 insertCoindispenseItem 方法与自动售货机进行交互。通过改变状态,自动售货机在不同的情况下表现出不同的行为。

适用场景

状态模式适用于以下场景:

  1. 对象的行为依赖于其状态,并且可以在运行时根据状态改变而改变行为。

    • 例如,一个文档编辑器,它可以处于编辑模式、预览模式和保存模式。不同模式下,工具栏和菜单的行为会有所不同。
  2. 对象有大量的条件语句来管理多个状态,并且这些条件语句使得代码难以维护和扩展。

    • 如果在代码中存在很多类似的if-else语句来处理对象的不同状态,状态模式可以帮助将这些状态的处理逻辑分散到不同的状态类中,使代码更清晰、可读性更好。
  3. 一个对象的状态转换在运行时可以发生,并且需要封装状态的变化。

    • 例如,在一个工作流应用中,一个任务可能有多个状态(待处理、处理中、已完成等),任务的状态可以在运行时发生变化,状态模式可以用来管理这些变化。
  4. 有些状态共享相同的行为,但在不同的状态下可能需要进行不同的处理。

    • 如果有几个状态在执行相同的操作时有共通的行为,但在细节上有所不同,状态模式可以减少重复代码,通过在每个状态类中实现相应的细节,使得代码更加模块化。
  5. 状态模式可以用于消除大量的条件性语句,提高代码的可维护性和可读性。

    • 当一个对象有多个状态,而这些状态在其行为上有明显的不同,使用状态模式可以将状态之间的转换和处理逻辑封装在独立的类中,使得代码更易于理解和维护。
相关推荐
sunbin15 分钟前
稀土掘金我要吐槽你
后端
程序员鱼皮2 小时前
我代表编程导航,向大家道歉!
前端·后端·程序员
间彧2 小时前
Spring Boot项目中如何实现Redis分布式锁
java
zjjuejin2 小时前
Maven 生命周期与插件机制
后端·maven
掘金安东尼2 小时前
AI 应用落地谈起 ,免费试用 Amazon Bedrock 的最佳时机
java·架构
阿杆2 小时前
为什么我建议你把自建 Redis 迁移到云上进行托管
redis·后端
杨杨杨大侠2 小时前
案例03-附件E-部署运维
java·docker·github
Java水解2 小时前
go语言教程(全网最全,持续更新补全)
后端·go
杨杨杨大侠2 小时前
案例03-附件B-映射器实现
java·开源·github
杨杨杨大侠2 小时前
案例03-附件A-订单实体设计
java·开源·github