Java设计模式超详解--状态设计模式

一,初步理解

图片来源:浏览器找的,不是作者本人画的

生活中的很多事物都具有不同的状态,如何让不同状态能够自如切换不出错,是我们今天要解决的问题。

举个例子:

生活中常见的旋转门(要收费那种)

假如转门处于锁定状态LockedTurnstileState:

当投币事件发生(coin()方法时,转门将转换到非锁定状态,并且执行解锁动作(Turnstile类的unLock()方法)。

假如转门处于非锁定状态UnLockedTurnstileState:

当有人通过门(pass()方法)时,转门将转换到锁定状态,并且将执行锁定动作(Turnstile类的lock()方法)。

当转门处于锁定状态,当有人通过门时 ,执行警告动作 (Turnstile类的alarm()方法)

当转门已经处于非锁定状态,当投币事件发生,执行谢谢动作(Turnstile类的thankYou()方法)

整理一下题目逻辑我们发现,大概是这个逻辑:

那大家肯定发现,一个简单的思维导图显然无法满足我们的逻辑需求(因为有一部分循环逻辑),所以为大家介绍状态图:

通过该状态图能更加清晰地看出我们的逻辑,接下来,结合我们刚刚讲到的类图 ,分析一下该题目的类图该怎么画:

首先

根据题目,很容易得到:

类图中的**ContextState(具体状态)**表示对应题目中的

LockedTurnstileState(表示锁住的状态)

UnLockedTurnstileState (表示未锁的状态)

那现在我们还需要写的是

State(与状态相关的行为)

作为**ContextState(具体状态)**的父类,需要写清楚状态行为的具体函数,如coin()与pass()

Context(当前状态)

需要写清楚当前状态的所有方法与行为

具体类图如下:

下面是详细代码实现
TurnstileState

java 复制代码
/**
 * 转门状态接口:定义转门所有状态需要实现的核心行为(投币、通过)
 * 状态模式的核心:将不同状态的行为封装到各自的实现类中,转门类仅负责状态切换
 */
interface TurnstileState {
    /**
     * 投币行为:不同状态下投币的处理逻辑不同,由具体状态类实现
     */
    void coin();

    /**
     * 通行行为:不同状态下通行的处理逻辑不同,由具体状态类实现
     */
    void pass();
}

Turnstile:

java 复制代码
class Turnstile {
    // 转门的两个核心状态对象:锁定状态、未锁定状态(提前初始化,复用对象)
    private TurnstileState lockedState;
    private TurnstileState unlockedState;
    // 转门当前的状态(初始值虽为lockedState,但构造方法中会重新初始化,后续main方法也会显式设置)
    private TurnstileState state = lockedState;

    /**
     * 构造方法:初始化转门的两个状态对象,并关联当前转门实例
     */
    public Turnstile() {
        // 创建锁定状态对象,传入当前转门实例
        lockedState = new LockedTurnstileState(this);
        // 创建未锁定状态对象,传入当前转门实例
        unlockedState = new UnLockedTurnstileState(this);
    }

    /**
     * 获取锁定状态对象(供状态切换时使用)
     * @return 锁定状态实例
     */
    public TurnstileState getLockedState() {
        return lockedState;
    }

    /**
     * 获取未锁定状态对象(供状态切换时使用)
     * @return 未锁定状态实例
     */
    public TurnstileState getUnlockedState() {
        return unlockedState;
    }

    /**
     * 切换转门的当前状态
     * @param state 新的状态对象
     */
    public void setState(TurnstileState state) {
        this.state = state;
    }

    /**
     * 投币行为委托:将投币逻辑交给当前状态对象处理
     */
    public void coin() {
        state.coin();
    }

    /**
     * 通行行为委托:将通行逻辑交给当前状态对象处理
     */
    public void pass() {
        state.pass();
    }

    /**
     * 解锁动作:转门解锁时的具体行为(打印提示)
     */
    public void unLock() {
        System.out.println("turnstile unlock");
    }

    /**
     * 锁定动作:转门锁定时的具体行为(打印提示)
     */
    public void lock() {
        System.out.println("turnstile lock");
    }

    /**
     * 警报动作:转门被强行通过时的具体行为(打印提示)
     */
    public void alarm() {
        System.out.println("alarm");
    }

    /**
     * 感谢提示动作:重复投币时的具体行为(打印提示,注意:原拼写错误"think you"已保留,如需修正可改为"thank you")
     */
    public void thankYou() {
        System.out.println("think you");
    }
}

LockedTurnstileState(表示锁住的状态)

UnLockedTurnstileState (表示未锁的状态)
重点!!!

java 复制代码
/**
 * 锁定状态实现类:实现转门"锁定"状态下的投币、通行逻辑
 */
class LockedTurnstileState implements TurnstileState {
    // 持有转门对象的引用,用于调用转门的方法(解锁、切换状态、触发警报等)
    private Turnstile turnstile;

    /**
     * 构造方法:初始化时传入转门对象,建立状态与转门的关联
     * @param turnstile 转门核心对象
     */
    public LockedTurnstileState(Turnstile turnstile) {
        this.turnstile = turnstile;
    }

    /**
     * 锁定状态下投币:
     * 1. 调用转门的解锁方法
     * 2. 将转门状态切换为"未锁定"状态
     */
    @Override
    public void coin() {
        turnstile.unLock(); // 执行解锁动作
        turnstile.setState(turnstile.getUnlockedState()); // 切换状态
    }

    /**
     * 锁定状态下通行:
     * 转门处于锁定状态时有人强行通过,触发警报
     */
    @Override
    public void pass() {
        turnstile.alarm(); // 执行警报动作
    }
}

/**
 * 未锁定状态实现类:实现转门"未锁定"状态下的投币、通行逻辑
 */
class UnLockedTurnstileState implements TurnstileState {
    // 持有转门对象的引用,用于调用转门的方法(感谢提示、锁定、切换状态等)
    private Turnstile turnstile;

    /**
     * 构造方法:初始化时传入转门对象,建立状态与转门的关联
     * @param turnstile 转门核心对象
     */
    public UnLockedTurnstileState(Turnstile turnstile) {
        this.turnstile = turnstile;
    }

    /**
     * 未锁定状态下投币:
     * 转门已解锁时再次投币,仅触发"感谢"提示,不切换状态
     */
    @Override
    public void coin() {
        turnstile.thankYou(); // 执行感谢提示动作
    }

    /**
     * 未锁定状态下通行:
     * 1. 调用转门的锁定方法
     * 2. 将转门状态切换为"锁定"状态
     */
    @Override
    public void pass() {
        turnstile.lock(); // 执行锁定动作(核心:原错误为unLock,已修正)
        turnstile.setState(turnstile.getLockedState()); // 切换状态
    }
}

/**
 * 转门核心类:管理转门的状态,委托状态类处理具体行为
 * 状态模式的上下文(Context):持有状态对象,提供状态切换和行为委托的能力
 */

二,题目练习

某大型商场内安装了多个简易的纸巾售卖机,自动出售2元钱一包的纸巾,且每次仅售出一包纸巾。纸巾售卖机的状态图如下图所示:

纸巾售卖机状态图

采用状态(State)模式来实现该纸巾售卖机,得到如下图所示的类图。其中类State为抽象类,定义了投币、退币、出纸巾等方法接口。类SoldState、SoldOutState、NoQuarterState和HasQuarterState分别对应图6-1中纸巾售卖机的4种状态:售出纸巾、纸巾售完、没有投币、有2元钱。

类 图

本题完整的代码结构如下:

java 复制代码
abstract class State {

    protected TissueMachine tissueMachine;



    public void insertQuarter()//投币

    {

    }



    public void ejectQuarter()//退币

    {

    }



    public void turnCrank() //按下"出纸巾"按钮

    {

    }



    public void dispense() //出纸巾

    {

    }



    public abstract void printState();

}



class TissueMachine {

    private State soldOutState, noQuarterState, hasQuarterState, soldState, state;

    private int count; //纸巾数



    public TissueMachine(int numbers) {

        count = numbers;

        soldOutState = new SoldOutState(this);

        noQuarterState = new NoQuarterState(this);

        hasQuarterState = new HasQuarterState(this);

        soldState = new SoldState(this);

        state = noQuarterState;

    }



    public State getHasQuarterState() {

        return hasQuarterState;

    }



    public State getNoQuarterState() {

        return noQuarterState;

    }



    public State getSoldState() {

        return soldState;

    }



    public State getSoldOutState() {

        return soldOutState;

    }



    public int getCount() {

        return count;

    }



    public void setState(State state) {

        this.state = state;

    }



    public void printState() {

        this.state.printState();

    }



    public void insertQuarter()//投币

    {

        this.state.insertQuarter();

    }



    public void ejectQuarter()//退币

    {

        this.state.ejectQuarter();

    }



    public void turnCrank() //按下"出纸巾"按钮

    {

        this.state.turnCrank();

    }



    public void dispense() //出纸巾

    {

        this.state.dispense();

    }

}

/**

此部分为本题缺失的代码,需要你完成并提交!

**/

java 复制代码
public class Main {

    public static void main(String[] args) {

        TissueMachine tissueMachine = new TissueMachine(10);

        tissueMachine.printState();

        tissueMachine.insertQuarter();

        tissueMachine.printState();

        tissueMachine.ejectQuarter();

        tissueMachine.printState();

        tissueMachine.insertQuarter();

        tissueMachine.printState();

        tissueMachine.turnCrank();

        tissueMachine.printState();

        tissueMachine.dispense();

        tissueMachine.printState();

    }

}

请完成缺失的代码并提交!

输入描述

输出描述

NoQuarterState

HasQuarterState

NoQuarterState

HasQuarterState

SoldState

NoQuarterState

答案

java 复制代码
class HasQuarterState extends State {
    private TissueMachine tissueMachine;
public HasQuarterState(TissueMachine tissueMachine){
    this.tissueMachine=tissueMachine;
}
 public void ejectQuarter()//退币

    {
     tissueMachine. setState(tissueMachine. getNoQuarterState());
    }
    
    public void turnCrank() //按下"出纸巾"按钮
    {
    tissueMachine. setState(tissueMachine. getSoldState());
    }
    public void printState(){
    System.out.println("HasQuarterState");
}
}


 class NoQuarterState extends State{
     private TissueMachine tissueMachine;
     public NoQuarterState(TissueMachine tissueMachine){
    this.tissueMachine=tissueMachine;
}
 public void insertQuarter()//投币

    {
     tissueMachine. setState(tissueMachine. getHasQuarterState());
    }
      public void printState(){
    System.out.println("NoQuarterState");
}   


    }



class SoldState extends State{
    private TissueMachine tissueMachine;
     public SoldState(TissueMachine tissueMachine){
    this.tissueMachine=tissueMachine;
}
    public void dispense() //出纸巾

    {
        if(tissueMachine.getCount()>0)
        {
          tissueMachine. setState(tissueMachine. getNoQuarterState());
            
        }
    }
    public void printState(){
    System.out.println("SoldState");
    }

}




 class SoldOutState extends State{
     private TissueMachine tissueMachine;
 public SoldOutState(TissueMachine tissueMachine){
    this.tissueMachine=tissueMachine;
}
 public void printState(){
    System.out.println("SoldOutState");
}   

    }

三,总结

  • 当对象的行为随状态改变而变化时,考虑使用状态模式。
  • 状态模式适用于替代复杂的条件或分支语句

设计模式系列持续更新,欢迎关注博主~

希望对大家有用,祝您开心~(o゜▽゜)o☆,有问题欢迎交流,俺会改的✊

相关推荐
古城小栈3 小时前
教育科技:AI+Java 智能题库系统开发实践
java·人工智能·科技
BD_Marathon3 小时前
【JavaWeb】乱码问题_HTML_Tomcat日志_sout乱码问题
java·tomcat·html
冰冰菜的扣jio3 小时前
JVM中的垃圾回收详解
java·jvm
小肖爱笑不爱笑3 小时前
2025/12/16 HTML CSS
java·开发语言·css·html·web
刘孬孬沉迷学习3 小时前
GTP协议
开发语言·学习·5g·php·信息与通信
未若君雅裁3 小时前
JVM核心原理总结
java·jvm
q_19132846953 小时前
基于SpringBoot2+Vue2的装修报价网站
java·vue.js·spring boot·mysql·计算机毕业设计·演示文稿
章豪Mrrey nical3 小时前
数组扁平化的详解
开发语言·前端·javascript·面试