设计模式-状态模式

设计模式专栏



模式介绍

状态模式是一种行为型设计模式,它允许一个对象在其内部状态改变时改变它的行为,使其看起来就像改变了自身的类。

在状态模式中,对象的行为会随着其状态的不同而改变。这种模式的主要目标是将对象的状态独立出来,形成单独的状态类。通过设置不同的状态对象,可以让环境对象拥有不同的行为,而状态转换的行为对客户端是透明的。

状态模式主要包含以下几个角色:
环境(Context) :拥有多种状态的对象,由于环境类的状态存在多样性且在不同状态下对象的行为有所不同,因此将状态独立出来形成单独的状态类。
抽象状态类(State) :定义一个接口以封装与环境类的一个特定相关行为,在抽象状态类中声明了各种不同状态对应的方法,而且在子类中都进行了实现。
具体状态类(ConcreteState) :抽象状态类的子类,每一个子类实现一个与环境类的一个状态相关的行为,每一个具体状态类对应环境的一个具体状态。

通过使用状态模式,可以将复杂的对象行为分解为一系列简单的状态行为,使得代码更加清晰、可维护和可扩展。同时,通过将状态封装在不同的状态类中,可以方便地添加新的状态和行为,而不需要修改原有的代码。

模式特点

状态模式的主要特点包括:
结构清晰 :状态模式将与特定状态相关的行为局部化到一个状态中,并且将不同状态的行为分割开来,满足"单一职责原则"。
状态转换明确 :通过将不同的状态引入独立的对象中,使得状态转换变得更加明确,且减少对象间的相互依赖。
职责明确 :状态类职责明确,有利于程序的扩展。通过定义新的子类很容易地增加新的状态和转换。

然而,状态模式也有一些缺点:
增加系统的类与对象的个数 :使用状态模式必然会增加系统的类与对象的个数,这可能会增加系统的复杂性和开销。

结构与实现复杂:如果使用不当,会导致程序结构和代码的混乱。

  • 状态模式的优点主要包括:
  1. 对状态转换规则进行了封装,可以使用枚举类枚举出所有可能的状态,但需要在枚举状态之前确定状态的种类。
  2. 扩展性好,将所有与某个或者某些状态有关的行为放到了一个类对象中,这样方便管理,并且可以方便的新增状态,只需要改变对象状态就可以实现改变对象行为。
  3. 代码简洁好维护,状态模式允许状态转换逻辑和状态对象合为一体,而不是一个巨大的条件语句块。
  4. 可以让多个不同的环境对象共享一个状态的对象,这样减少系统中对象的数量。
  • 状态模式的缺点主要包括:
  1. 增加对象和系统类的个数。
  2. 结构与实现比较复杂,如果使用不当,可能会造成程序结构和代码给人感觉很混乱的。
  3. 对开闭原则支持不好。

应用场景

状态模式的应用场景包括:

一个对象存在多个状态,并且这些状态可以相互转换。在运行时刻,对象的行为可能会根据其状态的变化而变化。

操作中含有庞大的多分支的条件语句,且这些分支依赖于该对象的状态。这个状态通常用一个或多个枚举常量表示。通常有多个操作包含这一相同的条件结构。State模式将每一个条件分支放入一个独立的类中,使得可以根据对象自身的情况将对象的状态作为一个对象,这一对象可以不依赖于其他对象而独立变化。

例如,电梯的运行就属于状态模式,电梯的运行状态包括停止、上行和下行,在这些状态之间可以相互转换,并且不同状态下有不同的行为。

状态模式和策略模式区别

状态模式和策略模式在以下方面存在区别:

  1. 重点不同 :状态模式重点在各状态之间的切换,从而做不同的事情;而策略模式更侧重于根据具体情况选择策略,并不涉及切换。
  2. 行为不同 :状态模式不同状态下做的事情不同,而策略模式做的都是同一件事。反观状态模式,各个状态的同一方法做的是不同的事,不能互相替换。
  3. 封装内容不同 :状态模式封装了对象的状态,而策略模式封装算法或策略。因为状态是跟对象密切相关的,它不能被重用;而策略模式通过从Context中分离出策略或算法,我们可以重用它们。
  4. 持有Context的引用不同 :在状态模式中,每个状态通过持有Context的引用,来实现状态转移;但是每个策略都不持有Context的引用,它们只是被Context使用。
  5. 切换状态的自动程度不同 :状态模式将各个状态所对应的操作分离开来,即对于不同的状态,由不同的子类实现具体操作,不同状态的切换由子类实现,当发现传入参数不是自己这个状态所对应的参数,则自己给Context类切换状态;这种转换是"自动","无意识"的。
  6. 暴露性不同 :策略模式的客户端必须对所有的策略类相当了解,明确当前场景下各种策略的利弊,权衡在当前场景下应该使用哪种策略,也就是是说策略类对客户端是暴露的。

状态模式和策略模式在处理问题的侧重点、行为、封装内容、持有Context的引用、切换状态的自动程度以及暴露性方面都存在明显的区别。

代码示例

Java实现状态模式

下面是一个Java实现状态模式的示例:

java 复制代码
// State接口
interface State {
    void handle(Context context);
}

// ConcreteStateA类
class ConcreteStateA implements State {
    @Override
    public void handle(Context context) {
        System.out.println("State A is active. Handling request...");
        context.setState(new ConcreteStateB());
    }
}

// ConcreteStateB类
class ConcreteStateB implements State {
    @Override
    public void handle(Context context) {
        System.out.println("State B is active. Handling request...");
        context.setState(new ConcreteStateA());
    }
}

// Context类
class Context {
    private State state;

    public Context(State state) {
        this.state = state;
    }

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

    public void request() {
        state.handle(this);
    }
}

// Client代码
public class Client {
    public static void main(String[] args) {
        Context context = new Context(new ConcreteStateA());
        context.request(); // 输出 "State A is active. Handling request..."
        context.request(); // 输出 "State B is active. Handling request..."
        context.request(); // 输出 "State A is active. Handling request...",状态在A和B之间切换。
    }
}

在这个示例中,我们定义了一个State接口,它包含一个handle()方法。然后我们创建了两个实现State接口的类ConcreteStateAConcreteStateB,它们分别实现了handle()方法。在ConcreteStateA中,我们将状态设置为ConcreteStateB,在ConcreteStateB中,我们将状态设置为ConcreteStateA。这样,当客户端调用request()方法时,状态就会在A和B之间切换。在客户端代码中,我们首先创建一个Context对象,并设置初始状态为ConcreteStateA。然后我们连续调用request()方法,可以看到状态在A和B之间切换,并输出相应的信息。

python实现状态模式

以下是一个Python实现状态模式的示例:

python 复制代码
class State:
    def handle(self, context):
        pass

class ConcreteStateA(State):
    def handle(self, context):
        print("State A is active. Handling request...")
        context.setState(ConcreteStateB())

class ConcreteStateB(State):
    def handle(self, context):
        print("State B is active. Handling request...")
        context.setState(ConcreteStateA())

class Context:
    def __init__(self, state):
        self.state = state

    def setState(self, state):
        self.state = state

    def request(self):
        self.state.handle(self)

# Client code
context = Context(ConcreteStateA())
context.request()  # 输出 "State A is active. Handling request..."
context.request()  # 输出 "State B is active. Handling request..."
context.request()  # 输出 "State A is active. Handling request...",状态在A和B之间切换。

在这个示例中,我们定义了一个抽象状态类State,它包含一个handle()方法。然后我们创建了两个实现State的子类ConcreteStateAConcreteStateB,它们分别实现了handle()方法。在ConcreteStateA中,我们将状态设置为ConcreteStateB,在ConcreteStateB中,我们将状态设置为ConcreteStateA。这样,当客户端调用request()方法时,状态就会在A和B之间切换。在客户端代码中,我们首先创建一个Context对象,并设置初始状态为ConcreteStateA。然后我们连续调用request()方法,可以看到状态在A和B之间切换,并输出相应的信息。

状态模式在spring中的应用

在Spring框架中,状态模式的应用主要体现在对状态的管理和转换上。Spring框架提供了丰富的状态管理机制,使得开发者能够更加灵活地控制和管理应用程序的状态。

以下是一些在Spring中应用状态模式的示例:

  1. 状态管理 :Spring框架提供了状态管理的功能,例如通过@Stateful注解来声明一个状态类,并通过@State注解来指定当前状态。这样,开发者就可以在应用程序中定义不同的状态,并在需要时进行状态的转换。
  2. 状态转换 :Spring框架支持状态之间的转换。开发者可以通过实现Stateful接口或使用@Stateful注解来定义状态转换的方法。这些方法可以根据当前状态和输入参数来决定下一个状态,从而实现状态的自动转换。
  3. 状态存储 :Spring框架还提供了状态存储的功能。开发者可以通过实现StateStore接口或使用@StateStore注解来定义状态存储的逻辑。这样,应用程序的状态就可以被持久化到内存或数据库中,以便在需要时进行恢复。

Spring框架中的状态模式可以帮助开发者更加灵活地管理应用程序的状态,提高代码的可维护性和可扩展性。

相关推荐
触底反弹1 小时前
🤯 面试被问 AI Workflow 和 Agent 有啥区别?3 张图 + 2 段代码讲清楚!
人工智能·设计模式·面试
杨充1 天前
10.可测试性实战设计
设计模式·开源·代码规范
杨充1 天前
9.重构十二式的实战
设计模式·开源·代码规范
杨充1 天前
6.设计原则的全景图
设计模式·开源·全栈
杨充1 天前
2.面向对象的特性
设计模式
杨充1 天前
7.SOLID原则案例汇
设计模式·开源·全栈
杨充1 天前
8.反模式与坏味道
设计模式·开源·代码规范
杨充1 天前
3.接口vs抽象类比较
设计模式
咖啡八杯1 天前
文法、BNF与AST
java·设计模式·解释器模式·ast·文法