行为型模式 - 状态模式

文章目录

  • [1. 生活中的例子](#1. 生活中的例子)
    • [1.1 自动售货机 🎮](#1.1 自动售货机 🎮)
    • [1.2 汽车档位 🚗](#1.2 汽车档位 🚗)
    • [1.3 核心思想提炼 💡](#1.3 核心思想提炼 💡)
  • [2. 代码中的例子](#2. 代码中的例子)
    • [2.1 基础结构📦](#2.1 基础结构📦)
    • [2.2 自动售货机 🛒](#2.2 自动售货机 🛒)
    • [2.2 交通信号灯 🚦](#2.2 交通信号灯 🚦)
  • [3. 归纳总结](#3. 归纳总结)
    • [3.1 状态模式核心总结 📊](#3.1 状态模式核心总结 📊)
    • [3.2 ✅ 状态模式的优点](#3.2 ✅ 状态模式的优点)
    • [3.3 使用时机⚠️](#3.3 使用时机⚠️)
    • [3.4 状态模式 vs 策略模式🔄](#3.4 状态模式 vs 策略模式🔄)
  • [4. 补充知识💡](#4. 补充知识💡)
    • [4.1 状态管理的方式](#4.1 状态管理的方式)
    • [4.2 状态共享](#4.2 状态共享)

1. 生活中的例子

1.1 自动售货机 🎮

场景: 想象一台自动售货机,它有几种状态:

  • 待机状态:等待投币
  • 已投币状态:已经投入了钱
  • 出货状态:正在出货
  • 缺货状态:商品卖完了

生动比喻: 售货机就像一个会变身的机器人

  • 当它是"待机机器人"时,只会说:"请投币"
  • 当变成"已投币机器人"时,会说:"请选择商品"
  • 当变成"出货机器人"时,会说:"正在出货,请稍等"
  • 当变成"缺货机器人"时,会说:"商品已售罄"

关键点: 同一个售货机,在不同状态下,对同一个按钮(比如"按按钮")的反应完全不同!

1.2 汽车档位 🚗

场景: 汽车有P(停车)、R(倒车)、N(空档)、D(行驶)等档位

生动比喻: 汽车变速箱就是一个状态机

  • P档状态:踩油门 → 车子不动(保护状态)
  • R档状态:踩油门 → 车子倒退
  • D档状态:踩油门 → 车子前进
  • N档状态:踩油门 → 发动机空转,车子不动

讲解: 同样的"踩油门"动作,在不同档位状态下产生完全不同的结果!这就是状态模式的核心思思。

1.3 核心思想提炼 💡

就像一个人在不同情绪状态下,对同一句话的反应不同:

  • 开心时听到批评 → 一笑而过
  • 生气时听到批评 → 大发雷霆
  • 悲伤时听到批评 → 更加难过

状态模式就是:让对象在不同状态下改变它的行为,就像变了一个人一样!

2. 代码中的例子

2.1 基础结构📦

状态模式三要素

java 复制代码
// 1. 状态接口(定义所有状态共有的行为)
interface State {
    void handle(Context context);
}

// 2. 具体状态类(实现不同状态下的行为)
class ConcreteStateA implements State { 
   @Override
   public void handle(Context context) {
      System.out.println("当前是状态A,执行A的行为");
      context.setState(new ConcreteStateB()); // 切换到下一个状态
  }
}

class ConcreteStateB implements State {
    @Override
    public void handle(Context context) {
       System.out.println("当前是状态B,执行B的行为");
       context.setState(new ConcreteStateA()); // 切换回状态A    
    }
}

// 3. 上下文类(持有状态引用)
class Context {
    private State state; 
    
    public Context(State state) {
       this.state = state;
    }
    
    public void setState(State state) {
       this.state = state;
    }
    
    public void request() {
       state.handle(this); // 委托给当前状态处理
    }
}

2.2 自动售货机 🛒

java 复制代码
import java.util.HashMap;
import java.util.Map;

// 状态接口
interface VendingMachineState {
    void insertCoin(VendingMachine machine);
    void pressButton(VendingMachine machine);
    void dispense(VendingMachine machine);
}

// 具体状态类
class IdleState implements VendingMachineState {
    @Override
    public void insertCoin(VendingMachine machine) {
        System.out.println("✅ 硬币已投入");
        machine.setState(new HasCoinState());
    }
    
    @Override
    public void pressButton(VendingMachine machine) {
        System.out.println("❌ 请先投入硬币");
    }
    
    @Override
    public void dispense(VendingMachine machine) {
        System.out.println("❌ 请先投入硬币并选择商品");
    }
}

class HasCoinState implements VendingMachineState {
    @Override
    public void insertCoin(VendingMachine machine) {
        System.out.println("❌ 已投入硬币,请先选择商品");
    }
    
    @Override
    public void pressButton(VendingMachine machine) {
        if (machine.getStock() > 0) {
            System.out.println("✅ 商品选择成功,准备出货");
            machine.setState(new DispensingState());
        } else {
            System.out.println("❌ 商品已售罄,退回硬币");
            machine.setState(new IdleState());
        }
    }
    
    @Override
    public void dispense(VendingMachine machine) {
        System.out.println("❌ 请先选择商品");
    }
}

class DispensingState implements VendingMachineState {
    @Override
    public void insertCoin(VendingMachine machine) {
        System.out.println("❌ 正在出货,请稍候");
    }
    
    @Override
    public void pressButton(VendingMachine machine) {
        System.out.println("❌ 正在出货,请稍候");
    }
    
    @Override
    public void dispense(VendingMachine machine) {
        machine.releaseProduct();
        System.out.println("✅ 商品已出货,感谢购买");
        machine.reduceStock();
        machine.setState(machine.getStock() > 0 ? new IdleState() : new SoldOutState());
    }
}

class SoldOutState implements VendingMachineState {
    @Override
    public void insertCoin(VendingMachine machine) {
        System.out.println("❌ 商品已售罄,无法投币");
    }
    
    @Override
    public void pressButton(VendingMachine machine) {
        System.out.println("❌ 商品已售罄");
    }
    
    @Override
    public void dispense(VendingMachine machine) {
        System.out.println("❌ 商品已售罄");
    }
}

// 上下文类 - 自动售货机
class VendingMachine {
    private VendingMachineState state;
    private int stock;
    private Map<String, Integer> products;
    
    public VendingMachine(int stock) {
        this.stock = stock;
        this.state = new IdleState();
        this.products = new HashMap<>();
        products.put("可乐", 3);
        products.put("薯片", 5);
    }
    
    public void setState(VendingMachineState state) {
        this.state = state;
    }
    
    public int getStock() {
        return stock;
    }
    
    public void reduceStock() {
        if (stock > 0) stock--;
    }
    
    public void releaseProduct() {
        System.out.println("机器发出商品...");
    }
    
    // 用户操作
    public void insertCoin() {
        state.insertCoin(this);
    }
    
    public void pressButton() {
        state.pressButton(this);
    }
    
    public void dispense() {
        state.dispense(this);
    }
}

// 测试代码
public class StatePatternDemo {
    public static void main(String[] args) {
        System.out.println("=== 自动售货机状态模式演示 ===\n");
        
        VendingMachine machine = new VendingMachine(2);
        
        // 场景1:正常购买流程
        System.out.println("【场景1:正常购买】");
        machine.insertCoin();  // 投币
        machine.pressButton(); // 选择商品
        machine.dispense();    // 出货
        
        System.out.println("\n【场景2:再次购买】");
        machine.insertCoin();
        machine.pressButton();
        machine.dispense();
        
        System.out.println("\n【场景3:售罄后尝试购买】");
        machine.insertCoin();  // 应该失败
    }
}

2.2 交通信号灯 🚦

java 复制代码
// 状态接口
interface TrafficLightState {
    void change(TrafficLight light);
    void showSignal();
}

// 具体状态
class RedLightState implements TrafficLightState {
    @Override
    public void change(TrafficLight light) {
        System.out.println("红灯 → 绿灯");
        light.setState(new GreenLightState());
    }
    
    @Override
    public void showSignal() {
        System.out.println("🔴 红灯:停止通行");
    }
}

class GreenLightState implements TrafficLightState {
    @Override
    public void change(TrafficLight light) {
        System.out.println("绿灯 → 黄灯");
        light.setState(new YellowLightState());
    }
    
    @Override
    public void showSignal() {
        System.out.println("🟢 绿灯:可以通行");
    }
}

class YellowLightState implements TrafficLightState {
    @Override
    public void change(TrafficLight light) {
        System.out.println("黄灯 → 红灯");
        light.setState(new RedLightState());
    }
    
    @Override
    public void showSignal() {
        System.out.println("🟡 黄灯:准备停止");
    }
}

// 上下文
class TrafficLight {
    private TrafficLightState state;
    
    public TrafficLight() {
        this.state = new RedLightState(); // 初始状态为红灯
    }
    
    public void setState(TrafficLightState state) {
        this.state = state;
    }
    
    public void change() {
        state.change(this);
    }
    
    public void show() {
        state.showSignal();
    }
}

// 测试
public class TrafficLightDemo {
    public static void main(String[] args) throws InterruptedException {
        TrafficLight light = new TrafficLight();
        
        // 模拟交通灯循环
        for (int i = 0; i < 6; i++) {
            light.show();
            Thread.sleep(1000);
            light.change();
        }
    }
}

3. 归纳总结

3.1 状态模式核心总结 📊

要素 现实 类比
Context(上下文) 拥有状态的对象,维护当前状态 自动售货机本体
State(状态接口) 定义所有状态的共同行为规范 "售货机状态"的职位描述
ConcreteState(具体状态) 实现特定状态下的行为 具体的"待机状态"、"出货状态"等

3.2 ✅ 状态模式的优点

  1. 单一职责原则:每个状态类只负责自己的行为
  2. 开闭原则:新增状态只需添加新类,无需修改已有代码
  3. 消除条件语句:用多态代替复杂的if-else或switch-case
  4. 状态转换明确:状态转移逻辑清晰可见

3.3 使用时机⚠️

当出现以下情况时考虑使用:

  • 对象的行为取决于它的状态,并且必须在运行时根据状态改变行为
  • 有大量的状态判断逻辑(if-else或switch)
  • 状态之间有明确的转换关系
  • 相似的状态和转换出现在多个地方

3.4 状态模式 vs 策略模式🔄

很多人容易混淆,关键区别:

  • 状态模式:状态之间相互知道,会自动转换(红灯知道下一个是绿灯)
  • 策略模式:策略之间相互独立,由客户端选择使用哪个策略

4. 补充知识💡

4.1 状态管理的方式

java 复制代码
// 方式1:由Context管理状态转换(推荐)
class Order {
    private OrderState state;
    
    public void nextState() {
        state = state.next(); // 状态类返回下一个状态
    }
}

// 方式2:由具体状态类管理转换
class PaidState implements OrderState {
    @Override
    public OrderState next() {
        return new ShippedState(); // 返回下一个状态实例
    }
}

4.2 状态共享

如果状态是无状态的(不包含成员变量),可以共享同一个实例:

java 复制代码
// 享元模式 + 状态模式
class StateFactory {
    private static final Map<String, State> states = new HashMap<>();
    
    static {
        states.put("IDLE", new IdleState());
        states.put("BUSY", new BusyState());
    }
    
    public static State getState(String key) {
        return states.get(key);
    }
}
相关推荐
AM越.12 小时前
Java设计模式详解--装饰器设计模式(含uml图)
java·设计模式·uml
qianshanxue1116 小时前
0-3论软件设计模式及其应用、2016-已写(观察者通知,命令-控制指令,适配器-兼容,工厂-多种数据库)
数据库·设计模式
syt_10131 天前
设计模式之-状态模式
javascript·设计模式·状态模式
山沐与山1 天前
【设计模式】Python仓储模式:从入门到实战
python·设计模式
游戏23人生1 天前
c++ 语言教程——17面向对象设计模式(六)
开发语言·c++·设计模式
GoKu~1 天前
DDD设计模式例子
设计模式
山沐与山1 天前
【设计模式】Python观察者模式:用RabbitMQ+Celery实现事件驱动
python·观察者模式·设计模式·rabbitmq
会飞的架狗师2 天前
DDD笔记 | 实体、值对象、聚合、聚合根
设计模式·设计规范
wanghowie2 天前
01.08 Java基础篇|设计模式深度解析
java·开发语言·设计模式