设计模式-状态模式

发布时间:2023年12月21日
设计模式专栏


模式介绍

状态模式是一种行为型设计模式,它允许一个对象在其内部状态改变时改变它的行为,使其看起来就像改变了自身的类。
在状态模式中,对象的行为会随着其状态的不同而改变。这种模式的主要目标是将对象的状态独立出来,形成单独的状态类。通过设置不同的状态对象,可以让环境对象拥有不同的行为,而状态转换的行为对客户端是透明的。
状态模式主要包含以下几个角色:
环境(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实现状态模式的示例:

// 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实现状态模式的示例:

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

在这里插入图片描述

文章来源:https://blog.csdn.net/zhangzehai2234/article/details/135120067
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。