Bootstrap

设计模式之 状态模式

状态模式(State Pattern)是一种行为型设计模式,它允许一个对象在其内部状态改变时,改变其行为。这种模式将状态的转换和行为的变化解耦,将不同状态的行为封装到独立的状态类中,而通过上下文(Context)来管理当前状态。每个状态类都负责处理与自己相关的行为,并且能够根据当前的状态转移到下一个状态。

状态模式的主要优点是可以避免在单一类中出现复杂的条件判断语句,增强系统的可扩展性和维护性。

一、状态模式的定义

状态模式允许一个对象在其内部状态改变时,改变其行为。也就是说,状态模式的核心思想是,状态的改变不仅仅是数据的变化,还会影响到行为的变化。每个状态类都有自己的行为实现,而当对象的状态发生变化时,它会切换到一个新的状态对象,这个新的状态对象将根据当前的状态执行相应的行为。

二、状态模式的组成部分

状态模式主要由以下几个部分构成:

  1. Context(上下文)

    上下文类负责维护当前状态并向外界提供一个接口。它还负责在状态变化时更新当前状态对象。上下文通过一个指向状态接口的引用来调用当前状态的行为。
  2. State(状态接口)

    定义一个状态接口,表示对象在不同状态下的行为。每个具体状态类都实现这个接口,并根据当前状态执行具体的操作。
  3. ConcreteState(具体状态类)

    具体的状态类,它实现了状态接口,封装了与该状态相关的行为。每个状态类的实现将描述在该状态下的具体行为和可能的状态转换。

三、状态模式的工作原理

状态模式的工作原理是将对象的所有可能状态封装在状态类中。当对象的状态发生变化时,通过上下文切换到新的状态类,并由新的状态类处理相应的行为。每个状态类内有自己处理请求的逻辑,状态类之间是独立的,并且状态的变化是由上下文自动控制的。

这种模式使得客户端不需要知道具体的状态类,只需要知道当前状态是什么,调用上下文的 request() 方法即可。

四、状态模式的代码示例

假设我们有一个简单的订单处理系统,其中订单的状态有多个,如 待支付已支付已发货 等,每个状态下的订单处理行为不同。

  • 定义状态接口
    public interface State {
        public void handleOrder(Context context);
    }
  • 创建具体状态类
    public class PendingPaymentState implements State{
    
        @Override
        public void handleOrder(Context context) {
            System.out.println("订单已支付");
            context.setState(new PaidState());
        }
    }
    public class PaidState implements State{
        @Override
        public void handleOrder(Context context) {
            System.out.println("订单已发货");
            context.setState(new ShippedState());
        }
    }
    
    public class CompletedState implements State{
        @Override
        public void handleOrder(Context context) {
            System.out.println("订单已完成");
        }
    }
  • 定义上下文类
    public class Context {
        private State state;
    
        public Context(State state) {
            this.state = state;
        }
    
        public void setState(State state) {
            this.state = state;
        }
    
        public void handle(){
            state.handleOrder(this);
        }
    }
  • 客户端代码
    public class Client {
        public static void main(String[] args) {
            Context context = new Context(new PendingPaymentState());
            context.handle();
            context.handle();
            context.handle();
    
        }
    }
  • 运行结果

五、状态模式的优缺点

优点:
  1. 消除复杂的条件判断:状态模式将状态行为与状态的转换分离,避免了在单一类中使用大量 ifswitch 语句。每个状态类只处理其对应状态下的行为,状态之间的切换逻辑也被隔离到不同的类中。

  2. 灵活性和扩展性:当需要增加新的状态时,只需要添加一个新的状态类,而不需要修改现有的代码。这符合开放封闭原则(对扩展开放,对修改关闭)。

  3. 代码更加清晰和易于维护:状态模式将不同的状态行为抽象为独立的类,这使得代码更加模块化,易于理解和维护。

  4. 容易实现状态切换:每个状态类都有自己的行为,当上下文需要切换状态时,只需更新上下文的状态属性即可。状态切换过程封装在状态类中,避免了外部操作的干扰。

缺点:
  1. 类的数量增加:每个状态都会对应一个具体的类,因此如果状态很多,会导致类的数量增加,可能使得系统结构变得复杂。

  2. 状态间切换的耦合性:虽然状态类的行为是独立的,但状态切换本身是通过上下文进行的,可能会导致上下文与状态之间的耦合性较强。

  3. 状态间的过度共享:在某些情况下,不同的状态之间可能有相似的行为或状态转换逻辑,可能导致一些冗余的代码。虽然可以通过抽象层次来减少重复,但也可能增加理解和维护的难度。

六、状态模式的应用场景

  1. 有多个状态的对象:状态模式非常适用于对象有多个不同的状态,并且不同状态下的行为各不相同的场景。比如在一个自动售货机的状态变化过程中,机器根据支付情况、货物是否有库存等条件改变行为。

  2. 工作流管理:在复杂的工作流系统中,每个任务的状态往往决定了任务的处理方式。使用状态模式可以使得每个任务的状态和行为更加清晰独立。

  3. 游戏开发:在游戏中,角色或场景的状态(例如“待机”、“行走”、“攻击”)常常影响到角色的行为。使用状态模式能够简化这些状态的管理。

  4. 事务管理系统:例如订单的不同阶段(如待支付、已支付、已发货等)可能会有不同的处理方法,状态模式能够很好的将不同阶段的处理逻辑分离开来。

;