设计模式第21讲——状态模式(State)

状态模式是一种行为型设计模式,允许对象在内部状态改变时改变其行为。模式中包含上下文、抽象状态和具体状态角色。优点包括解耦客户端和状态对象,可扩展性强,避免大量条件语句。缺点是可能增加系统类的数量和复杂性。适用场景如自动售货机的状态转换、线程状态管理等。代码示例展示了自动售卖机如何利用状态模式实现不同状态的切换。
摘要由CSDN通过智能技术生成

一、什么是状态模式

状态模式是一种行为型设计模式。它允许对象在内部状态发生改变时改变它的行为,简单地讲就是,一个拥有状态的context对象,在不同状态下,其行为会发生改变。

二、角色组成

  • 上下文(Context):定义客户端需要的接口,并且负责具体状态的切换。
  • 抽象状态(Abstract State):抽象状态类是所有具体状态类的基类或接口。负责定义该状态下的行为,可以一个或多个。
  • 具体状态(Concrete State):具体状态类实现了抽象状态类定义的接口,并根据当前状态决定上下文对象的行为。

三、 优缺点

优点:

  • 客户端只需要与上下文对象进行交互,而不需要了解具体状态对象的切换和行为实现细节。
  • 状态模式遵循开闭原则,使系统更加可扩展。当需要增加新的状态时,只需添加新的具体状态类,而无需修改上下文对象或其他状态类。
  • 避免了使用大量的条件语句来控制对象在不同状态下的行为。它将状态相关的代码分散到各个具体状态类中,使代码更加清晰、可读性更高,易于维护和扩展。
  • 状态转换被封装在具体状态类中,可根据需求定义不同的状态切换规则,使得状态转换过程可控、灵活。

缺点:

  • 状态模式增加了系统中类的数量,引入了更多的类,可能会增加代码的复杂性。
  • 对于简单、直接的状态机,使用状态模式可能会显得过于繁琐,增加了代码的冗余。在这种情况下,可以采用简化的条件语句来处理状态转换。

四、应用场景

 4.1 生活场景

  • 自动售货机:自动售货机中的商品状态会随着库存量的变化而改变。当库存为0时,商品状态为"售罄";当库存充足时,商品状态为"可购买";
  • 购物车状态:在线购物网站中,购物车可以有不同的状态,比如空、有商品、结算中等。每个状态下,购物车的显示内容和可用操作不同。

4.2 java场景

  • Thread类:线程有new、Runnable、Blocked、Waiting、Time_Waiting和Terminated状态。这些状态代表了线程在不同的执行阶段或操作中的不同状态。Thread类内部使用了状态模式来管理和切换线程的状态。
  • Connection接口:Connection接口表示与数据库的连接,它可能处于不同的状态,比如打开、关闭、空闲、繁忙等。Connection接口在不同的状态下提供了不同的操作方法,以便与数据库进行交互。

五、代码实现 

下面以自动售卖机为例,解释一下状态模式。我们可以将售卖机分为三个部分:自动售卖机(Machine)类作为上下文(Context),状态(State)作为状态的抽象状态(Abstract State),售卖机的三个状态——未投币(NoCoinState)、已投币(HasCoinState)、出售中(SlodState)作为具体状态(Concrete State)

5.0 UML类图

5.1 State——抽象状态

/**
 * @author Created by njy on 2023/7/3
 * 1.抽象状态(Abstract State):状态接口
 * 定义:定义该状态下的行为,可以一个或多个。
 */
public interface State {
    //投币
    void insertCoin();
    //选择商品
    void selectProduct();
    //发放商品
    void dispense();
}

5.2 具体状态

/**
 * @author Created by njy on 2023/7/3
 * 2.具体状态(Concrete State):未投币状态
 * 定义:实现了抽象状态类定义的接口,并根据当前状态决定上下文对象的行为。
 */
public class NoCoinState implements State{
    private Machine machine;

    public NoCoinState(Machine machine) {
        this.machine = machine;
    }

    @Override
    public void insertCoin() {
        System.out.println("已投币");
        // 切换到已投币状态
        machine.setState(machine.getHasCoinState());
    }

    @Override
    public void selectProduct() {
        System.out.println("请先投币");
    }

    @Override
    public void dispense() {
        System.out.println("请先投币选择商品");
    }
}
/**
 * @author Created by njy on 2023/7/3
 * 2.具体状态(Concrete State):已投币状态
 * 定义:实现了抽象状态类定义的接口,并根据当前状态决定上下文对象的行为。
 */
public class HasCoinState implements State{

    private Machine machine;

    public HasCoinState(Machine machine) {
        this.machine = machine;
    }

    @Override
    public void insertCoin() {
        System.out.println("已投币,请勿重复投币");
    }

    @Override
    public void selectProduct() {
        System.out.println("商品已选择");
        // 切换到出售状态
        machine.setState(machine.getSoldState());
    }

    @Override
    public void dispense() {
        System.out.println("请先选择商品");
    }
}
/**
 * @author Created by njy on 2023/7/3
 * 2.具体状态(Concrete State):出售状态
 * 定义:实现了抽象状态类定义的接口,并根据当前状态决定上下文对象的行为。
 */
public class SoldState implements State{
    private Machine machine;

    public SoldState(Machine machine) {
        this.machine = machine;
    }

    @Override
    public void insertCoin() {
        System.out.println("正在出售商品,请稍等");
    }

    @Override
    public void selectProduct() {
        System.out.println("正在出售商品,请稍等");
    }

    @Override
    public void dispense() {
        System.out.println("商品已发放");
        //切换到未投币状态
        machine.setState(machine.getNoCoinState());
    }
}

5.3 Machine——上下文

/**
 * @author Created by njy on 2023/7/3
 * 3.上下文(Context):自动售卖机
 * 定义:定义客户端需要的接口,并且负责具体状态的切换。
 */
public class Machine {
    //未投币状态
    private State noCoinState;
    //已投币状态
    private State hasCoinState;
    //出售状态
    private State soldState;
    //当前状态
    private State currentState;

    public Machine() {
        noCoinState = new NoCoinState(this);
        hasCoinState = new HasCoinState(this);
        soldState = new SoldState(this);
        currentState = noCoinState; // 初始状态为未投币状态
    }

    public void setState(State state) {
        currentState = state;
    }

    public State getNoCoinState() {
        return noCoinState;
    }

    public State getHasCoinState() {
        return hasCoinState;
    }

    public State getSoldState() {
        return soldState;
    }

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

    public void selectProduct() {
        currentState.selectProduct();
    }

    public void dispense() {
        currentState.dispense();
    }
}

5.4 testState

/**
 * @author Created by njy on 2023/7/3
 * 状态模式测试类
 */
@SpringBootTest
public class TestState {

    @Test
    void testState(){
        //创建上下文对象(自动售卖机)
        Machine machine = new Machine();

        System.out.println("=======直接选择商品=======");
        machine.selectProduct();

        System.out.println("======投币--->选择商品--->发放商品=======");
        machine.insertCoin();
        machine.selectProduct();
        machine.dispense();

        System.out.println("=======投币--->发放商品=======");
        machine.insertCoin();
        machine.dispense();
    }
}

 

六、总结

熟悉策略模式的小伙伴可能会发现,状态模式和策略模式的UML类图几乎一摸一样,但这两中模式的应用场景是不一样的。策略模式的多种算法行为选择一种就能满足,彼此之间是独立的;而状态模式中各个状态间存在相互关系,彼此之间在一定条件下存在自动切换状态的效果,并且用户不能指定状态,只能设置初始状态。

以下情况出现,可以考虑状态模式:

  • 当一个对象的行为取决于其内部状态,并且在不同状态下具有不同的行为时
  • 当对象的行为在运行时需要根据其状态动态改变,并且需要避免大量的条件语句和分支判断时。
  • 当代码中存在大量的条件语句和分支逻辑,并且这些逻辑与对象的状态变化相关时。
  • 当对象的状态之间存在复杂的转换关系,并且需要维护状态转换的一致性时。

END:更多设计模式的介绍,推荐移步至👉 23种设计模式学习导航(Java完整版)👈 

  • 13
    点赞
  • 80
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
在代码开发过程中,我们经常会遇到需要根据不同的条件执行不同的操作的情况。通常的做法是使用if-else语句来实现条件判断。但是,随着代码量的增加,if-else语句也会不断增多,代码变得越来越难以维护和扩展。为了解决这个问题,我们可以使用设计模式来重构代码,使其更加清晰、简洁和易于扩展。 状态模式是一种行为型设计模式,它允许对象在内部状态改变时改变它的行为。状态模式状态封装成独立的类,并将请求委托给当前的状态对象。当状态发生改变时,更改状态对象以及委托给它的请求处理。 下面我们以一个简单的电梯控制器为例,来演示如何使用状态模式来代替if-else语句。 首先,我们定义一个抽象的状态类: ```python class LiftState: def open(self): pass def close(self): pass def run(self): pass def stop(self): pass ``` 然后,我们定义具体的状态类,分别代表电梯处于打开、关闭、运行和停止状态: ```python class OpenState(LiftState): def open(self): print("电梯门已经打开了,不需要再打开了!") def close(self): print("电梯门关闭...") return CloseState() def run(self): print("电梯还没关门,不能上下楼!") def stop(self): print("电梯门已经打开了,不能停止!") class CloseState(LiftState): def open(self): print("电梯门打开...") return OpenState() def close(self): print("电梯门已经关闭了,不需要再关闭了!") def run(self): print("电梯开始运行...") return RunState() def stop(self): print("电梯已经停止了,不能再停止了!") class RunState(LiftState): def open(self): print("电梯正在运行,不能打开门!") def close(self): print("电梯正在运行,不能关闭门!") def run(self): print("电梯正在运行...") def stop(self): print("电梯停止运行...") return StopState() class StopState(LiftState): def open(self): print("电梯门打开...") return OpenState() def close(self): print("电梯已经停止了,不能关闭门!") def run(self): print("电梯开始运行...") return RunState() def stop(self): print("电梯已经停止了,不需要再停止了!") ``` 最后,我们定义一个电梯控制器类,用于控制电梯的状态: ```python class LiftController: def __init__(self): self.state = StopState() def set_state(self, state): self.state = state def open(self): self.state = self.state.open() def close(self): self.state = self.state.close() def run(self): self.state = self.state.run() def stop(self): self.state = self.state.stop() ``` 现在,我们可以通过调用电梯控制器类的方法来控制电梯的状态,而无需使用if-else语句: ```python lift_controller = LiftController() lift_controller.open() # 电梯门打开... lift_controller.close() # 电梯门关闭... lift_controller.run() # 电梯开始运行... lift_controller.stop() # 电梯停止运行... ``` 通过使用状态模式,我们可以将电梯控制器的不同状态封装成独立的类,使代码更加清晰、简洁和易于扩展。此外,状态模式还可以减少if-else语句的使用,提高代码的可读性和可维护性。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

橡 皮 人

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值