【设计模式-4.6】行为型——状态模式

说明:本文介绍行为型设计模式之一的状态模式

定义

状态模式(State Pattern)也叫作状态机模式(State Machine Pattern),允许对象在内部状态发生改变时改变它的行为,对象看起来好像修改了它的类,属于行为型设计模式。(引自《设计模式就该这样学》P348)

"对象看起来好像修改了它的类",指对象的状态发生改变后,与之对应的行为也会发生改变(当然,这取决于你的业务逻辑)。


状态模式中类的行为是由状态决定的,在不同的状态下有不同的行为。其意图是让一个对象在其内部改变的时候,行为也随之改变。状态模式的核心是状态与行为绑定,不同的状态对应不同的行为。(引自《设计模式就该这样学》P348)

这段讲的很好。

灯的状态

灯的状态简单来分,只有两种,开的和熄灭的,所以更换灯的状态,代码写出来,很简单,如下:

java 复制代码
/**
 * 灯开关
 */
public class Switcher {

    /**
     * 灯状态
     * false:熄灯
     * true:开灯
     */
    private boolean state = false;

    /**
     * 使开灯
     */
    public void switchOn() {
        state = true;
        System.out.println("开灯");
    }

    /**
     * 使熄灯
     */
    public void switchOff() {
        state = false;
        System.out.println("熄灯");
    }
}

作为程序员的严谨,需要考虑到灯在开启的时候,再调用开启方法的情况和灯在熄灭的时候,再调用熄灭方法的情况,如下:

java 复制代码
/**
 * 灯开关-Plus
 */
public class SwitcherPlus {

    /**
     * 灯状态
     * false:熄灯
     * true:开灯
     */
    private boolean state = false;

    public void switchOn() {
        // 如果是熄灯
        if (!state) {
            state = true;
            System.out.println("开灯");
        } else {
            System.out.println("灯已经是开灯状态,无需重复开灯");
        }
    }

    public void switchOff() {
        // 如果是开灯
        if (state) {
            state = false;
            System.out.println("熄灯");
        } else {
            System.out.println("灯已经是熄灭状态,无需重复熄灯");
        }
    }
}

代码变得复杂起来了,以上仅是一个对象,两种状态的情况,用if-else还能应付。如果是多个状态,例如交通信号灯,有红黄绿三个状态,绿灯变红灯,红灯变黄灯,黄灯变绿灯,代码如下:

java 复制代码
/**
 * 交通信号灯
 */
public class TrafficLight {

    /**
     * 信号灯状态,默认红
     * 红灯转绿灯,绿灯转黄灯,黄灯转红灯
     */
    private String state = "红";

    /**
     * 切换到绿灯
     */
    public void switchToGreen() {
        if ("绿".equals(state)) {
            System.out.println("已是绿灯,无需切换。。。");
        } else if ("红".equals(state)) {
            System.out.println("成功切换到绿灯~~~");
        } else if ("黄".equals(state)) {
            System.out.println("黄灯不能切换到绿灯!!!");
        }
    }

    /**
     * 切换到黄灯
     */
    public void switchToYellow() {
        if ("绿".equals(state)) {
            System.out.println("成功切换到黄灯~~~");
        } else if ("红".equals(state)) {
            System.out.println("红灯不能切换到黄灯!!!");
        } else if ("黄".equals(state)) {
            System.out.println("已是黄灯,无需切换。。。");
        }
    }

    /**
     * 切换到红灯
     */
    public void switchToRed() {
        if ("绿".equals(state)) {
            System.out.println("绿灯不能切换到红灯!!!");
        } else if ("红".equals(state)) {
            System.out.println("已是红灯,无需切换。。。");
        } else if ("黄".equals(state)) {
            System.out.println("成功切换到红灯~~~");
        }
    }
}

多层的if-else,代码显得臃肿,难以维护,后续涉及修改也会频繁改动这个类。

状态模式

使用状态模式,将方法、状态抽出来,如下:

(状态接口,State)

java 复制代码
/**
 * 状态
 */
public interface State {

    /**
     * 切换到绿灯
     */
    void switchToGreen(TrafficLight trafficLight);

    /**
     * 切换到黄灯
     */
    void switchToYellow(TrafficLight trafficLight);

    /**
     * 切换到红灯
     */
    void switchToRed(TrafficLight trafficLight);
}

(红灯实现类,Red,注意切换成功后修改状态)

java 复制代码
/**
 * 红灯
 */
public class Red implements State {

    @Override
    public void switchToGreen(TrafficLight trafficLight) {
        trafficLight.setState(new Green());
        System.out.println("成功切换到绿灯~~~");
    }

    @Override
    public void switchToYellow(TrafficLight trafficLight) {
        System.out.println("红灯不能切换到黄灯!!!");
    }

    @Override
    public void switchToRed(TrafficLight trafficLight) {
        System.out.println("已是红灯,无需切换。。。");
    }
}

(绿灯实现类,Green,注意切换成功后修改状态)

java 复制代码
/**
 * 绿灯
 */
public class Green implements State {

    @Override
    public void switchToGreen(TrafficLight trafficLight) {
        System.out.println("已是绿灯,无需切换。。。");
    }

    @Override
    public void switchToYellow(TrafficLight trafficLight) {
        trafficLight.setState(new Yellow());
        System.out.println("成功切换到黄灯~~~");
    }

    @Override
    public void switchToRed(TrafficLight trafficLight) {
        System.out.println("绿灯不能切换到红灯!!!");
    }
}

(黄灯实现类,Yellow,注意切换成功后修改状态)

java 复制代码
/**
 * 黄灯
 */
public class Yellow implements State {

    @Override
    public void switchToGreen(TrafficLight trafficLight) {
        System.out.println("黄灯不能切换到绿灯!!!");
    }

    @Override
    public void switchToYellow(TrafficLight trafficLight) {
        System.out.println("已是黄灯,无需切换。。。");
    }

    @Override
    public void switchToRed(TrafficLight trafficLight) {
        trafficLight.setState(new Red());
        System.out.println("成功切换到红灯~~~");
    }
}

(信号灯类,TrafficLight,只需调用抽象方法即可)

java 复制代码
/**
 * 交通信号灯
 */
public class TrafficLight {

    /**
     * 默认状态:红灯
     */
    State state = new Red();

    /**
     * 设置灯状态
     */
    public void setState(State state) {
        this.state = state;
    }

    /**
     * 切换到绿灯
     */
    public void switchToGreen() {
        state.switchToGreen(this);
    }

    /**
     * 切换到黄灯
     */
    public void switchToYellow() {
        state.switchToYellow(this);
    }

    /**
     * 切换到红灯
     */
    public void switchToRed() {
        state.switchToRed(this);
    }
}

(客户端,Client)

java 复制代码
public class Client {
    public static void main(String[] args) {
        TrafficLight trafficLight = new TrafficLight();

        trafficLight.switchToGreen();
        trafficLight.switchToYellow();
        trafficLight.switchToRed();
    }
}

执行如下

看下来,使用状态模式,减少了单个类使用大量if-else分支处理复杂逻辑的代码,使代码便于维护,后续还有其他状态,如粉灯、蓝灯,只需要增加对应的类,对应的抽象方法即可,不需要更改原来的代码。

综合来看,状态模式,将原本的代码(code)层面上的结构化,转为了类(class)层面上的结构化,这也是其他设计模式的大体思想。

使用场景

在《设计模式就该这样学》(P349)这本书中,提到状态模式适用于以下场景:

(1)行为随状态改变而改变的场景;

(2)一个操作中含有庞大的多分支结构,并且这些分支取决于对象的状态;

总结

本文介绍了行为型设计模式中的状态模式,参考《设计模式就该这样学》、《秒懂设计模式》两书,交通信号灯场景是《秒懂设计模式》中的举例。

相关推荐
鲨鱼辣钊15 分钟前
【FastAPI筑基-Day19】APScheduler定时任务全实战|自动执行、动态启停、后台常驻
java·spring·fastapi
学长毕业设计5 小时前
基于SpringBoot的公益基金管理系统(源码+文档+讲解视频)
java·spring boot·后端
东小西5 小时前
【SAA实战】第 3 篇 · 工具调用全攻略:把业务能力交给 Agent 自己调度
java·后端·spring
东小西5 小时前
【SAA实战】第 4 篇 · Agent 短期记忆:saver 让 Agent 跨轮记得住(threadId 隔离)
java·后端·spring
许彰午5 小时前
22-DataCenter报文序列化
java·低代码·架构·状态模式
2601_962065255 小时前
[MySQL] SQL优化之性能分析
java·sql·mysql
小范同学_5 小时前
JDK1.7 与 JDK1.8 HashMap 底层原理对比 + 数组并发扩容死循环详解
java·开发语言
予昊6 小时前
从零实现“在线五子棋对战“:WebSocket 实时通信 + 段位匹配
java·开发语言·网络·websocket
2601_962203517 小时前
【SpringAI入门】初识SpringAI
java
weixin_461408587 小时前
Mybatis-flex小记
java·开发语言·mybatis