状态模式

概述

很多情况下,一个对象的行为取决于一个或多个动态变化的属性,这样的属性叫做状态。一个对象可以拥有多个状态,这些状态可以相互转换,当对象状态不同时,其行为也有所差异

假设一个人就是对象,人根据心情不同会有很多状态,比如开心和伤心,这两种状态可以相互转换。开心的人可能会因为突然的噩耗而伤心,过了一段时间后,又可能因为其他好事而开心。不同状态下人的行为也不同,有些人伤心时会通过运动、旅行、听音乐来缓解心情,而开心时则可能会唱歌、跳舞、请客吃饭等等

再来考虑软件系统中的情况,如某酒店订房系统,可以将房间设计为一个类,房间对象有已预订、空闲、已入住等情况,这些状态之间可以相互转换,并且不同状态的对象可能具有不同的行为,如已预订或已入住的房间不能再接收其他顾客的预订,而空闲的房间可以接受预订

我们可以使用复杂的条件判断来进行状态判断和转换操作,这会导致代码的可维护性和灵活性下降,当出现新的状态时必须修改代码。在状态模式中,可以将对象状态从包含该状态的类中分离出来,做成一个单独的状态类,将状态和状态对应的行为分离


模式定义

允许一个对象在其内部状态改变时改变它的行为,对象看起来似乎修改了它的类。其别名为状态对象(Objects for States),状态模式是一种对象行为型模式。

Allow an object to alter its behavior when its internal state changes. The object will appear to change its class.


模式分析

我们把拥有状态的对象称为环境类,也叫上下文类。再引入一个抽象状态类来专门表示对象的状态,对象的每一种具体状态类都继承该抽象类,不同具体状态类实现不同状态的行为,包括各种状态之间的转换。在环境类中维护一个抽象状态类 State 的实例,用来定义当前状态

得到状态模式结构类图如下:

环境类中的 request() 方法处理业务逻辑,根据状态去调用对应的 handle() 方法,如果需要切换状态,还提供了 setState() 用于设置当前房间状态。如果我们希望执行操作后状态自动发生改变,那么我们还需要在 State 中定义一个 Context 对象,实现一个双向依赖关系

考虑前面提到的订房系统,如果不使用状态模式,可能就会存在如下代码:

if (state == "空闲") {
	if (预订房间) {
        预订操作;
        state = "已预订";
	} else if (住进房间) {
    	入住操作;
        state = "已入住";
    }
} else if(state == "已预订") {
	if (住进房间) {
        入住操作;
        state = "已入住";
	} else if (取消预订) {
    	取消操作;
        state = "空闲";
    }
}

上述代码需要做频繁且复杂的判断操作,可维护性很差。因此考虑使用状态模式将房间类的状态分离出来,将与每种状态有关的操作封装在独立的状态类中

来写一个完整的示例

环境类(Room)

public class Room {
	
    // 维护一个状态对象
    private State state;

    public Room() {
        // 默认为空闲状态
        this.state = new IdleState(this);
    }

    public State getState() {
        return state;
    }

    public void setState(State state) {
        this.state = state;
    }

    public void reserve() {
        state.reserve();
    }

    public void checkIn() {
        state.checkIn();
    }

    public void cancelReserve() {
        state.cancelReserve();
    }

    public void checkOut() {
        state.checkOut();
    }
}

抽象状态类(State)

public abstract class State {
	
    // 用于状态转换
    protected Room room;

    public State(Room room) {
        this.room = room;
    }

    public abstract void reserve();

    public abstract void checkIn();

    public abstract void cancelReserve();

    public abstract void checkOut();
}

具体状态类(IdleState)

public class IdleState extends State {

    public IdleState(Room room) {
        super(room);
    }

    @Override
    public void reserve() {
        System.out.println("房间预订成功");
        // 	切换状态
        room.setState(new ReservedState(room));
    }

    @Override
    public void checkIn() {
        System.out.println("房间入住成功");
        room.setState(new InhabitedState(room));
    }

    @Override
    public void cancelReserve() {
        System.out.println("无法取消预订,房间处于空闲状态");
    }

    @Override
    public void checkOut() {
        System.out.println("无法退房,房间处于空闲状态");
    }

}

具体状态类(ReservedState)

public class ReservedState extends State {

    public ReservedState(Room room) {
        super(room);
    }

    @Override
    public void reserve() {
        System.out.println("无法预订,房间处于已预订状态");
    }

    @Override
    public void checkIn() {
        System.out.println("房间入住成功");
        room.setState(new InhabitedState(room));
    }

    @Override
    public void cancelReserve() {
        System.out.println("取消预订成功");
        room.setState(new IdleState(room));
    }

    @Override
    public void checkOut() {
        System.out.println("无法退房,房间处于已预订状态");
    }
}

具体状态类(InhabitedState)

public class InhabitedState extends State {

    public InhabitedState(Room room) {
        super(room);
    }

    @Override
    public void reserve() {
        System.out.println("无法预订,房间处于入住状态");
    }

    @Override
    public void checkIn() {
        System.out.println("无法入住,房间处于入住状态");
    }

    @Override
    public void cancelReserve() {
        System.out.println("无法取消预订,房间处于入住状态");
    }

    @Override
    public void checkOut() {
        System.out.println("退房成功");
        room.setState(new IdleState(room));
    }
}

测试类(Client)

public class Client {

    public static void main(String[] args) {

        Room room = new Room();
        room.cancelReserve();
        room.checkOut();
        room.reserve();
        System.out.println("--------------------------");
        room.reserve();
        room.checkOut();
        room.checkIn();
        System.out.println("--------------------------");
        room.reserve();
        room.checkIn();
        room.cancelReserve();
        room.checkOut();
    }
}
posted @   低吟不作语  阅读(759)  评论(0编辑  收藏  举报
编辑推荐:
· 浏览器原生「磁吸」效果!Anchor Positioning 锚点定位神器解析
· 没有源码,如何修改代码逻辑?
· 一个奇形怪状的面试题:Bean中的CHM要不要加volatile?
· [.NET]调用本地 Deepseek 模型
· 一个费力不讨好的项目,让我损失了近一半的绩效!
阅读排行:
· 没有源码,如何修改代码逻辑?
· PowerShell开发游戏 · 打蜜蜂
· 在鹅厂做java开发是什么体验
· 百万级群聊的设计实践
· WPF到Web的无缝过渡:英雄联盟客户端的OpenSilver迁移实战
点击右上角即可分享
微信分享提示