【再谈设计模式】状态模式~对象行为的状态驱动者

简介: 状态模式属于行为型设计模式。它将对象的行为封装在不同的状态类中,使得对象在不同的状态下表现出不同的行为。上下文(Context):这是一个包含状态对象的类,它定义了客户感兴趣的接口,并维护一个具体状态对象的引用。上下文将操作委托给当前的状态对象来处理。抽象状态(State):这是一个抽象类或者接口,它定义了一个特定状态下的行为接口。所有具体的状态类都实现这个接口。具体状态(Concrete State):这些是实现抽象状态接口的类,每个具体状态类实现了与该状态相关的行为。

{B664E87D-286A-4B31-808A-15F47E3C470F}.png

一、引言

在软件开发,软件设计过程中,我们常常会遇到对象的行为依赖于其状态的情况。例如,一个任务对象可能有“未开始”、“进行中”、“已完成”等状态,并且在不同状态下执行相同操作会有不同的结果。传统的方法可能会使用大量的条件判断语句来处理不同状态下的行为,这使得代码复杂、难以维护且不易扩展。而状态模式提供了一种优雅的解决方案,它允许对象在内部状态改变时改变其行为,看起来就像是修改了类本身。

二、定义与描述

状态模式属于行为型设计模式。它将对象的行为封装在不同的状态类中,使得对象在不同的状态下表现出不同的行为。在状态模式中,有以下几个主要角色:
上下文(Context):这是一个包含状态对象的类,它定义了客户感兴趣的接口,并维护一个具体状态对象的引用。上下文将操作委托给当前的状态对象来处理。
抽象状态(State):这是一个抽象类或者接口,它定义了一个特定状态下的行为接口。所有具体的状态类都实现这个接口。
具体状态(Concrete State):这些是实现抽象状态接口的类,每个具体状态类实现了与该状态相关的行为。

三、抽象背景

考虑一个简单的订单处理系统。订单有不同的状态,如“已下单”、“已付款”、“已发货”、“已完成”等。在传统的设计中,如果要处理订单在不同状态下的操作(如显示订单状态、执行下一个流程等),可能会有如下的代码:
public class Order {
       private String state;    public Order(String state) {
           this.state = state;
    }    public void process() {
           if ("已下单".equals(state)) {
   
            System.out.println("订单已下单,等待付款");
        } else if ("已付款".equals(state)) {
   
            System.out.println("订单已付款,准备发货");
        } else if ("已发货".equals(state)) {
   
            System.out.println("订单已发货,等待收货");
        } else if ("已完成".equals(state)) {
   
            System.out.println("订单已完成");
        }
    }
}
    这种代码随着状态的增加和操作的复杂化会变得非常难以维护。而使用状态模式可以将每个状态的行为封装到独立的类中,使得代码结构更加清晰。

四、适用场景与现实问题解决

(一)适用场景

​    ​对象行为依赖于状态:当一个对象的行为根据其内部状态而改变时,状态模式非常合适。例如,游戏角色在不同的健康状态(满血、受伤、濒死)下有不同的行为(正常移动、缓慢移动、无法移动)。
​    ​避免大量条件判断:如果在代码中有大量的基于对象状态的条件判断语句,使用状态模式可以将这些判断分散到各个状态类中,提高代码的可读性和可维护性。

(二)现实问题解决

    以自动售货机为例,它有“空闲”、“投币”、“出货”等状态。如果使用传统的条件判断来处理每个状态下的操作(如投币操作在不同状态下的不同行为),代码会变得复杂且容易出错。而采用状态模式,可以清晰地定义每个状态下的行为,并且当需要添加新的状态或者修改现有状态的行为时,只需要在相应的状态类中进行修改,而不会影响到其他部分的代码。

{FE382273-E880-4B3A-8736-B7C2FDB6861A}.png

五、状态模式的现实生活的例子

    交通信号灯就是一个很好的状态模式的例子。交通信号灯有红、黄、绿三种状态,在不同的状态下,车辆和行人有不同的行为。例如,红灯时车辆停止,绿灯时车辆通行,黄灯时车辆减速准备停车。每个状态都有其对应的行为规则,并且状态之间可以按照一定的顺序转换。

{A1CD7739-1DB7-4C40-9B6B-C6EE392708AC}.png

六、初衷与问题解决

    初衷是为了更好地处理对象状态相关的行为,使得代码结构更加清晰、易于维护和扩展。通过将状态相关的行为封装到独立的状态类中,解决了传统方式中大量条件判断带来的代码复杂、不易理解和修改困难的问题。

七、代码示例

(一)Java示例

{C3AF4088-1590-4CBB-8F3C-D8B6FED8955E}.png
抽象状态接口

interface State {
       void handle(Context 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);
    }
}
    具体状态类示例(以两种状态为例)
class ConcreteStateA implements State {
       @Override
    public void handle(Context context) {
   
        System.out.println("ConcreteStateA处理请求");        // 状态转换示例
        context.setState(new ConcreteStateB());
    }
}class ConcreteStateB implements State {
       @Override
    public void handle(Context context) {
   
        System.out.println("ConcreteStateB处理请求");        // 状态转换示例
        context.setState(new ConcreteStateA());
    }
}
![{
   44CA60C6-30C9-41C5-9116-82AB4304B8F0}.png](https://ucc.alicdn.com/pic/developer-ecology/h6pyagd6fll2i_9b697bac86b34394ba9c91d50653527b.png)
    测试代码

{D2F534D7-30E7-4740-BF4A-629234E6E2BA}.png

public class Main {
       public static void main(String[] args) {
           Context context = new Context(new ConcreteStateA());
        context.request();
        context.request();
    }
}

(二)C++示例

    抽象状态类
class State {
   public:    virtual void handle(Context* context) = 0;
};
    上下文类
class Context {
   private:
    State* state;public:    Context(State* state) : state(state) {
   }    void setState(State* state) {
           this.state = state;
    }    void request() {
   
        state->handle(this);
    }
};
    具体状态类示例(以两种状态为例)
class ConcreteStateA : public State {
   public:    void handle(Context* context) override {
   
        std::cout << "ConcreteStateA处理请求" << std::endl;        // 状态转换示例
        context->setState(new ConcreteStateB());
    }
};class ConcreteStateB : public State {
   public:    void handle(Context* context) override {
   
        std::cout << "ConcreteStateB处理请求" << std::endl;        // 状态转换示例
        context->setState(new ConcreteStateA());
    }
};
    测试代码
int main() {
   
    Context* context = new Context(new ConcreteStateA());
    context->request();
    context->request();    return 0;
}

(三)Python示例

    抽象状态类(使用抽象基类实现)
from abc import ABC, abstractmethodclass State(ABC):   
   @abstractmethod def handle(self, context):       
                       pass
    上下文类
class Context:    def __init__(self, state):
        self.state = state    def setState(self, state):
        self.state = state    def request(self):
        self.state.handle(self)
    具体状态类示例(以两种状态为例)
class ConcreteStateA(State):    def handle(self, context):        print("ConcreteStateA处理请求")        # 状态转换示例
        context.setState(ConcreteStateB())class ConcreteStateB(State):    def handle(self, context):        print("ConcreteStateB处理请求")
   # 状态转换示例
 ```js

context.setState(ConcreteStateA())


        测试代码

```js
if __name__ == "__main__":
    context = Context(ConcreteStateA())
    context.request();
    context.request();

(四)Go示例

    抽象状态接口
type State interface {
   
    handle(context *Context)
}
    上下文结构体
type Context struct {
   
    state State
}func (c *Context) setState(state State) {
   
    c.state = state
}func (c *Context) request() {
   
    c.state.handle(c)
}
    具体状态结构体示例(以两种状态为例)
type ConcreteStateA struct{
   }func (c ConcreteStateA) handle(context *Context) {
       println("ConcreteStateA处理请求")    // 状态转换示例
    context.setState(ConcreteStateB{
   })
}type ConcreteStateB struct{
   }func (c ConcreteStateB) handle(context *Context) {
       println("ConcreteStateB处理请求")    // 状态转换示例
    context.setState(ConcreteStateA{
   })
}
    测试代码
func main() {
   
    context := &Context{
   state: ConcreteStateA{
   }}
    context.request()
    context.request()
}

八、状态模式的优缺点

(一)优点

​    ​提高代码的可维护性:将每个状态的行为封装到独立的类中,使得代码结构清晰,易于理解和修改。当需要添加新的状态或者修改现有状态的行为时,只需要在相应的状态类中进行操作,而不会影响到其他部分的代码。
​    ​符合开闭原则:对扩展开放,对修改关闭。可以轻松地添加新的状态类而不需要修改原有的上下文类和其他状态类的代码。
​    ​增强代码的可读性:避免了大量的条件判断语句,使得代码逻辑更加直观。

(二)缺点

​    ​类的数量增加:每个状态都需要一个对应的状态类,这可能会导致类的数量过多,特别是在状态比较复杂或者状态数量较多的情况下。
​    ​状态转换逻辑分散:状态之间的转换逻辑分布在各个状态类中,如果状态转换比较复杂,可能会导致代码的理解和维护成本增加。

{EAC0443C-9C7B-4739-868F-B6D9CFC40C86}.png

九、状态模式的升级版

    一种常见的升级版是引入状态机框架。状态机框架可以更加方便地管理状态之间的转换关系,提供了统一的状态转换规则配置方式。例如,在一些游戏开发中使用的有限状态机(FSM)框架,它可以预先定义好所有的状态和状态之间的转换条件,然后在游戏运行过程中根据实际情况进行状态转换。这样不仅提高了状态管理的效率,还使得整个状态处理流程更加清晰、可控。

{08E44E43-5F50-46A3-B537-6ED41D785F89}.png

目录
相关文章
|
9月前
|
设计模式 网络协议 数据可视化
Java 设计模式之状态模式:让对象的行为随状态优雅变化
状态模式通过封装对象的状态,使行为随状态变化而改变。以订单为例,将待支付、已支付等状态独立成类,消除冗长条件判断,提升代码可维护性与扩展性,适用于状态多、转换复杂的场景。
1063 157
|
设计模式 网络协议 Java
【设计模式】【行为型模式】状态模式(State)
一、入门 什么是状态模式? 状态模式(State Pattern)是一种行为设计模式,允许对象在其内部状态改变时改变其行为,使其看起来像是改变了类。状态模式的核心思想是将对象的状态封装成独立的类,并将
486 16
|
设计模式 存储 Java
【再谈设计模式】备忘录模式~对象状态的守护者
备忘录模式属于行为型设计模式。它的主要目的是在不破坏对象封装性的前提下,捕获并外部化一个对象的内部状态,以便之后可以将该对象恢复到这个状态。原发器(Originator):创建一个备忘录,用于记录当前时刻它的内部状态。原发器还可以使用备忘录来恢复其内部状态。备忘录(Memento):存储原发器对象的内部状态。备忘录应该防止原发器以外的其他对象访问其内部状态。负责人(Caretaker):负责保存备忘录,但不能对备忘录的内容进行操作或检查。
511 82
|
设计模式 供应链 安全
【再谈设计模式】中介者模式 - 协调对象间交互的枢纽
中介者模式定义了一个中介对象来封装一组对象之间的交互方式。中介者使得各对象之间不需要显式地相互引用,从而降低了它们之间的耦合度。它通过将对象之间的交互逻辑集中到中介者对象中,使得系统的结构更加清晰,易于维护和扩展。
433 18
【再谈设计模式】中介者模式 - 协调对象间交互的枢纽
|
设计模式 算法 Java
【再谈设计模式】访问者模式~操作对象结构的新视角
  访问者模式是一种行为设计模式,旨在解决对象结构与操作逻辑的耦合问题。在软件系统开发中,当面临复杂的对象结构(如多种类型对象组成的树形或图形结构),且需要对这些对象执行不同操作时,传统方式将操作直接写在对象类中会导致类职责过多,不利于维护和扩展。而访问者模式通过将操作与对象结构分离,允许在不改变现有对象结构的情况下定义新操作,元素接受访问者访问,访问者定义对不同类型元素的操作逻辑,从而为应对这种复杂情况提供了有效的解决方案。
322 0
|
设计模式 Java 数据库连接
【设计模式】【创建型模式】工厂方法模式(Factory Methods)
一、入门 什么是工厂方法模式? 工厂方法模式(Factory Method Pattern)是一种创建型设计模式,它定义了一个用于创建对象的接口,但由子类决定实例化哪个类。工厂方法模式使类的实例化延迟
392 16
|
设计模式 负载均衡 监控
并发设计模式实战系列(2):领导者/追随者模式
🌟 ​大家好,我是摘星!​ 🌟今天为大家带来的是并发设计模式实战系列,第二章领导者/追随者(Leader/Followers)模式,废话不多说直接开始~
386 0
|
设计模式 监控 Java
并发设计模式实战系列(1):半同步/半异步模式
🌟 ​大家好,我是摘星!​ 🌟今天为大家带来的是并发设计模式实战系列,第一章半同步/半异步(Half-Sync/Half-Async)模式,废话不多说直接开始~
559 0
|
设计模式 安全 Java
并发设计模式实战系列(12):不变模式(Immutable Object)
🌟 大家好,我是摘星!🌟今天为大家带来的是并发设计模式实战系列,第十二章,废话不多说直接开始~
317 0
|
设计模式 前端开发 搜索推荐
前端必须掌握的设计模式——模板模式
模板模式(Template Pattern)是一种行为型设计模式,父类定义固定流程和步骤顺序,子类通过继承并重写特定方法实现具体步骤。适用于具有固定结构或流程的场景,如组装汽车、包装礼物等。举例来说,公司年会节目征集时,蜘蛛侠定义了歌曲的四个步骤:前奏、主歌、副歌、结尾。金刚狼和绿巨人根据此模板设计各自的表演内容。通过抽象类定义通用逻辑,子类实现个性化行为,从而减少重复代码。模板模式还支持钩子方法,允许跳过某些步骤,增加灵活性。
989 11

热门文章

最新文章