行为型模式:⑧状态模式(State Pattern)

行为型模式:⑧状态模式(State Pattern)

核心思想

将对象的状态封装为独立的“状态类”,对象的行为由当前状态决定,当对象的内部状态发生变化时,其行为也会随之改变(如同“换了一种身份”)。核心价值是:

  • 消除大量if-else/switch条件判断,将状态相关的行为分散到具体状态类中,代码更清晰、可维护;
  • 状态切换逻辑封装在状态类内部,对象无需关心状态实现细节,仅需持有当前状态引用;
  • 新增状态时无需修改现有代码(包括对象和其他状态),仅需新增状态类,符合“开闭原则”。

核心本质

状态封装+行为委托,将“状态-行为”的映射关系从对象中抽离,由状态类自主管理,实现状态与对象的解耦。

典型场景

  • 有限状态机(如电梯、红绿灯、订单流程);
  • 对象行为随状态动态变化(如播放器的播放/暂停/停止状态);
  • 复杂条件判断导致代码臃肿(如超过3个状态且每个状态行为不同)。

C语言实现(结构体+函数指针+状态委托)

C语言无类和继承,通过“结构体模拟角色”“函数指针定义状态行为接口”“环境类持有当前状态指针”,实现状态与行为的解耦。核心是:环境类将行为委托给当前状态,状态类通过修改环境类的“当前状态指针”实现切换。

场景示例

电梯状态管理系统:

  • 环境类(Elevator):持有当前楼层、目标楼层、当前状态,提供触发事件的接口(按楼层、按开门、按关门、超时);
  • 抽象状态(ElevatorState):用函数指针定义统一行为接口(处理按楼层、按开门、按关门、超时);
  • 具体状态:待机(IdleState)、运行(RunningState)、开门(OpeningState)、关门(ClosingState),实现各自的行为逻辑和状态切换。

实现代码

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

// 前置声明:环境类(电梯),供状态类使用
typedef struct Elevator Elevator;

// -------------------------- 1. 抽象状态(ElevatorState):统一行为接口 --------------------------
typedef struct ElevatorState {
    // 状态名称(用于打印日志)
    const char* name;
    // 处理按楼层事件
    void (*handle_floor)(Elevator* elevator, int target_floor);
    // 处理按开门事件
    void (*handle_open)(Elevator* elevator);
    // 处理按关门事件
    void (*handle_close)(Elevator* elevator);
    // 处理超时事件(如开门后自动关门)
    void (*handle_timeout)(Elevator* elevator);
} ElevatorState;

// -------------------------- 2. 环境类(Elevator):电梯上下文 --------------------------
struct Elevator {
    int current_floor;   // 当前楼层
    int target_floor;    // 目标楼层(-1表示无目标)
    ElevatorState* current_state; // 持有当前状态指针(核心)
    // 事件触发接口(客户端调用)
    void (*press_floor)(Elevator* self, int target_floor);
    void (*press_open)(Elevator* self);
    void (*press_close)(Elevator* self);
    void (*timeout)(Elevator* self);
    void (*destroy)(Elevator* self);
};

// -------------------------- 3. 具体状态实现(待机、运行、开门、关门) --------------------------
// 前置声明具体状态(相互引用时需要)
extern ElevatorState IdleState;
extern ElevatorState RunningState;
extern ElevatorState OpeningState;
extern ElevatorState ClosingState;

// --------------- 具体状态1:待机状态(IdleState)---------------
// 待机时按楼层:设置目标楼层,切换到运行状态
void idle_handle_floor(Elevator* elevator, int target_floor) {
    if (target_floor == elevator->current_floor) {
        printf("[%s] 当前已在%d楼,无需运行\n", elevator->current_state->name, target_floor);
        return;
    }
    printf("[%s] 收到目标楼层%d,开始运行...\n", elevator->current_state->name, target_floor);
    elevator->target_floor = target_floor;
    elevator->current_state = &RunningState; // 切换到运行状态
}

// 待机时按开门:切换到开门状态
void idle_handle_open(Elevator* elevator) {
    printf("[%s] 收到开门指令,开始开门...\n", elevator->current_state->name);
    elevator->current_state = &OpeningState; // 切换到开门状态
}

// 待机时按关门:无动作(已关门)
void idle_handle_close(Elevator* elevator) {
    printf("[%s] 已处于关门状态,无需操作\n", elevator->current_state->name);
}

// 待机时超时:无动作
void idle_handle_timeout(Elevator* elevator) {
    printf("[%s] 待机超时,无操作\n", elevator->current_state->name);
}

// 待机状态实例
ElevatorState IdleState = {
    .name = "待机状态",
    .handle_floor = idle_handle_floor,
    .handle_open = idle_handle_open,
    .handle_close = idle_handle_close,
    .handle_timeout = idle_handle_timeout
};

// --------------- 具体状态2:运行状态(RunningState)---------------
// 运行时按楼层:更新目标楼层(不切换状态)
void running_handle_floor(Elevator* elevator, int target_floor) {
    printf("[%s] 运行中收到新目标楼层%d,更新目标...\n", elevator->current_state->name, target_floor);
    elevator->target_floor = target_floor;
}

// 运行时按开门:无效(运行中不能开门)
void running_handle_open(Elevator* elevator) {
    printf("[%s] 运行中无法开门,操作无效\n", elevator->current_state->name);
}

// 运行时按关门:无效(已关门)
void running_handle_close(Elevator* elevator) {
    printf("[%s] 运行中已关门,无需操作\n", elevator->current_state->name);
}

// 运行时超时:到达目标楼层,切换到开门状态
void running_handle_timeout(Elevator* elevator) {
    printf("[%s] 到达目标楼层%d,停止运行,准备开门...\n", 
           elevator->current_state->name, elevator->target_floor);
    elevator->current_floor = elevator->target_floor; // 更新当前楼层
    elevator->target_floor = -1; // 清空目标
    elevator->current_state = &OpeningState; // 切换到开门状态
}

// 运行状态实例
ElevatorState RunningState = {
    .name = "运行状态",
    .handle_floor = running_handle_floor,
    .handle_open = running_handle_open,
    .handle_close = running_handle_close,
    .handle_timeout = running_handle_timeout
};

// --------------- 具体状态3:开门状态(OpeningState)---------------
// 开门时按楼层:记录目标,关门后运行
void opening_handle_floor(Elevator* elevator, int target_floor) {
    printf("[%s] 开门中收到目标楼层%d,关门后运行...\n", elevator->current_state->name, target_floor);
    elevator->target_floor = target_floor;
}

// 开门时按开门:无动作(已开门)
void opening_handle_open(Elevator* elevator) {
    printf("[%s] 已处于开门状态,无需操作\n", elevator->current_state->name);
}

// 开门时按关门:切换到关门状态
void opening_handle_close(Elevator* elevator) {
    printf("[%s] 收到关门指令,开始关门...\n", elevator->current_state->name);
    elevator->current_state = &ClosingState; // 切换到关门状态
}

// 开门时超时:自动关门,切换到关门状态
void opening_handle_timeout(Elevator* elevator) {
    printf("[%s] 开门超时(3秒),自动关门...\n", elevator->current_state->name);
    elevator->current_state = &ClosingState; // 切换到关门状态
}

// 开门状态实例
ElevatorState OpeningState = {
    .name = "开门状态",
    .handle_floor = opening_handle_floor,
    .handle_open = opening_handle_open,
    .handle_close = opening_handle_close,
    .handle_timeout = opening_handle_timeout
};

// --------------- 具体状态4:关门状态(ClosingState)---------------
// 关门时按楼层:设置目标,切换到运行状态
void closing_handle_floor(Elevator* elevator, int target_floor) {
    if (target_floor == elevator->current_floor) {
        printf("[%s] 当前已在%d楼,切换到待机状态\n", elevator->current_state->name, target_floor);
        elevator->target_floor = -1;
        elevator->current_state = &IdleState;
        return;
    }
    printf("[%s] 收到目标楼层%d,关门后运行...\n", elevator->current_state->name, target_floor);
    elevator->target_floor = target_floor;
    elevator->current_state = &RunningState; // 切换到运行状态
}

// 关门时按开门:切换到开门状态
void closing_handle_open(Elevator* elevator) {
    printf("[%s] 收到开门指令,重新开门...\n", elevator->current_state->name);
    elevator->current_state = &OpeningState; // 切换到开门状态
}

// 关门时按关门:无动作(已关门)
void closing_handle_close(Elevator* elevator) {
    printf("[%s] 已处于关门状态,无需操作\n", elevator->current_state->name);
}

// 关门时超时:无目标则切换到待机,有目标则切换到运行
void closing_handle_timeout(Elevator* elevator) {
    if (elevator->target_floor == -1) {
        printf("[%s] 关门超时,无目标楼层,切换到待机状态\n", elevator->current_state->name);
        elevator->current_state = &IdleState; // 切换到待机
    } else {
        printf("[%s] 关门超时,有目标楼层%d,开始运行...\n", 
               elevator->current_state->name, elevator->target_floor);
        elevator->current_state = &RunningState; // 切换到运行
    }
}

// 关门状态实例
ElevatorState ClosingState = {
    .name = "关门状态",
    .handle_floor = closing_handle_floor,
    .handle_open = closing_handle_open,
    .handle_close = closing_handle_close,
    .handle_timeout = closing_handle_timeout
};

// -------------------------- 环境类(Elevator)方法实现 --------------------------
// 按楼层事件
void elevator_press_floor(Elevator* self, int target_floor) {
    if (target_floor < 1 || target_floor > 10) { // 假设电梯1-10楼
        printf("无效楼层%d(仅支持1-10楼)\n", target_floor);
        return;
    }
    self->current_state->handle_floor(self, target_floor); // 委托给当前状态处理
}

// 按开门事件
void elevator_press_open(Elevator* self) {
    self->current_state->handle_open(self); // 委托给当前状态处理
}

// 按关门事件
void elevator_press_close(Elevator* self) {
    self->current_state->handle_close(self); // 委托给当前状态处理
}

// 超时事件(模拟自动触发)
void elevator_timeout(Elevator* self) {
    self->current_state->handle_timeout(self); // 委托给当前状态处理
}

// 销毁环境类
void elevator_destroy(Elevator* self) {
    free(self);
    printf("电梯系统已关闭\n");
}

// 创建电梯(环境类)
Elevator* create_elevator() {
    Elevator* elevator = (Elevator*)malloc(sizeof(Elevator));
    elevator->current_floor = 1;    // 初始楼层1楼
    elevator->target_floor = -1;    // 初始无目标
    elevator->current_state = &IdleState; // 初始状态:待机
    elevator->press_floor = elevator_press_floor;
    elevator->press_open = elevator_press_open;
    elevator->press_close = elevator_press_close;
    elevator->timeout = elevator_timeout;
    elevator->destroy = elevator_destroy;
    printf("电梯初始化完成,当前状态:%s,当前楼层:%d\n", 
           elevator->current_state->name, elevator->current_floor);
    return elevator;
}

// -------------------------- 测试代码(客户端) --------------------------
int main() {
    // 1. 创建电梯
    Elevator* elevator = create_elevator();
    printf("========================================\n");

    // 2. 模拟电梯操作流程
    // 步骤1:待机状态按3楼
    elevator->press_floor(elevator, 3);
    // 步骤2:运行状态超时(到达3楼)
    elevator->timeout(elevator);
    // 步骤3:开门状态超时(自动关门)
    elevator->timeout(elevator);
    // 步骤4:关门状态按5楼
    elevator->press_floor(elevator, 5);
    // 步骤5:运行状态按开门(无效)
    elevator->press_open(elevator);
    // 步骤6:运行状态超时(到达5楼)
    elevator->timeout(elevator);
    // 步骤7:开门状态按关门
    elevator->press_close(elevator);
    // 步骤8:关门状态超时(无目标,切换到待机)
    elevator->timeout(elevator);
    // 步骤9:待机状态按1楼(当前已在5楼,运行)
    elevator->press_floor(elevator, 1);
    printf("========================================\n");

    // 3. 销毁电梯
    elevator->destroy(elevator);

    return 0;
}

C语言实现关键要点

  1. 抽象状态接口(函数指针)ElevatorState结构体通过函数指针定义handle_floor/handle_open等统一接口,所有具体状态都实现这些接口,确保环境类可通过统一方式调用状态行为。
  2. 环境类持有当前状态Elevatorcurrent_state指针指向当前状态,行为委托给当前状态处理,环境类无需关心具体状态逻辑。
  3. 状态自主切换:状态切换逻辑封装在具体状态类的行为函数中(如idle_handle_floor切换到RunningState),环境类不参与状态切换决策,符合“单一职责原则”。
  4. 无if-else判断:客户端和环境类均无状态相关的条件判断,新增/修改状态时无需修改现有代码,仅需调整状态类,符合“开闭原则”。
  5. 内存管理:具体状态为全局静态变量(无需动态分配),环境类手动malloc/free,避免内存泄漏;状态切换仅修改指针,无额外内存开销。
  6. 扩展性:新增状态(如“故障状态”)时,仅需定义新的ElevatorState实例并实现函数指针,修改相关状态的切换逻辑,无需改动环境类和客户端。

C++实现(类+继承+多态+智能指针)

C++通过“抽象基类+继承”定义状态接口,利用多态实现状态行为的动态分发,环境类持有抽象状态的指针(或智能指针),状态切换通过修改指针指向实现,代码更符合面向对象风格。

实现代码

#include <iostream>
#include <string>
#include <memory> // 智能指针

using namespace std;

// 前置声明:环境类(电梯),供状态类使用
class Elevator;

// -------------------------- 1. 抽象状态(ElevatorState):抽象基类 --------------------------
class ElevatorState {
public:
    virtual ~ElevatorState() = default; // 虚析构:确保子类析构被调用
    // 纯虚函数:定义状态行为接口
    virtual void handleFloorPress(Elevator& elevator, int target_floor) = 0;
    virtual void handleOpenPress(Elevator& elevator) = 0;
    virtual void handleClosePress(Elevator& elevator) = 0;
    virtual void handleTimeout(Elevator& elevator) = 0;
    // 获取状态名称(用于日志)
    virtual string getName() const = 0;
};

// -------------------------- 2. 环境类(Elevator):电梯上下文 --------------------------
class Elevator {
public:
    Elevator() 
        : current_floor_(1), target_floor_(-1) {
        // 初始状态:待机状态(智能指针管理)
        current_state_ = make_unique<IdleState>();
        cout << "电梯初始化完成,当前状态:" << current_state_->getName() 
             << ",当前楼层:" << current_floor_ << endl;
    }

    // 事件触发接口(客户端调用)
    void pressFloor(int target_floor) {
        if (target_floor < 1 || target_floor > 10) {
            cout << "无效楼层" << target_floor << "(仅支持1-10楼)" << endl;
            return;
        }
        current_state_->handleFloorPress(*this, target_floor); // 多态调用当前状态行为
    }

    void pressOpen() {
        current_state_->handleOpenPress(*this);
    }

    void pressClose() {
        current_state_->handleClosePress(*this);
    }

    void timeout() {
        current_state_->handleTimeout(*this);
    }

    // 状态切换接口(供状态类调用)
    template <typename StateType>
    void switchState() {
        current_state_ = make_unique<StateType>();
        cout << "[状态切换] → " << current_state_->getName() << endl;
    }

    // getter/setter(供状态类访问上下文)
    int getCurrentFloor() const { return current_floor_; }
    int getTargetFloor() const { return target_floor_; }
    void setCurrentFloor(int floor) { current_floor_ = floor; }
    void setTargetFloor(int floor) { target_floor_ = floor; }

private:
    int current_floor_;                // 当前楼层
    int target_floor_;                 // 目标楼层(-1表示无目标)
    unique_ptr<ElevatorState> current_state_; // 当前状态(智能指针自动管理内存)
};

// -------------------------- 3. 具体状态类实现 --------------------------
// --------------- 具体状态1:待机状态(IdleState)---------------
class IdleState : public ElevatorState {
public:
    string getName() const override { return "待机状态"; }

    void handleFloorPress(Elevator& elevator, int target_floor) override {
        if (target_floor == elevator.getCurrentFloor()) {
            cout << "[" << getName() << "] 当前已在" << target_floor << "楼,无需运行" << endl;
            return;
        }
        cout << "[" << getName() << "] 收到目标楼层" << target_floor << ",开始运行..." << endl;
        elevator.setTargetFloor(target_floor);
        elevator.switchState<RunningState>(); // 切换到运行状态
    }

    void handleOpenPress(Elevator& elevator) override {
        cout << "[" << getName() << "] 收到开门指令,开始开门..." << endl;
        elevator.switchState<OpeningState>(); // 切换到开门状态
    }

    void handleClosePress(Elevator& elevator) override {
        cout << "[" << getName() << "] 已处于关门状态,无需操作" << endl;
    }

    void handleTimeout(Elevator& elevator) override {
        cout << "[" << getName() << "] 待机超时,无操作" << endl;
    }
};

// --------------- 具体状态2:运行状态(RunningState)---------------
class RunningState : public ElevatorState {
public:
    string getName() const override { return "运行状态"; }

    void handleFloorPress(Elevator& elevator, int target_floor) override {
        cout << "[" << getName() << "] 运行中收到新目标楼层" << target_floor << ",更新目标..." << endl;
        elevator.setTargetFloor(target_floor);
    }

    void handleOpenPress(Elevator& elevator) override {
        cout << "[" << getName() << "] 运行中无法开门,操作无效" << endl;
    }

    void handleClosePress(Elevator& elevator) override {
        cout << "[" << getName() << "] 运行中已关门,无需操作" << endl;
    }

    void handleTimeout(Elevator& elevator) override {
        int target = elevator.getTargetFloor();
        cout << "[" << getName() << "] 到达目标楼层" << target << ",停止运行,准备开门..." << endl;
        elevator.setCurrentFloor(target); // 更新当前楼层
        elevator.setTargetFloor(-1);      // 清空目标
        elevator.switchState<OpeningState>(); // 切换到开门状态
    }
};

// --------------- 具体状态3:开门状态(OpeningState)---------------
class OpeningState : public ElevatorState {
public:
    string getName() const override { return "开门状态"; }

    void handleFloorPress(Elevator& elevator, int target_floor) override {
        cout << "[" << getName() << "] 开门中收到目标楼层" << target_floor << ",关门后运行..." << endl;
        elevator.setTargetFloor(target_floor);
    }

    void handleOpenPress(Elevator& elevator) override {
        cout << "[" << getName() << "] 已处于开门状态,无需操作" << endl;
    }

    void handleClosePress(Elevator& elevator) override {
        cout << "[" << getName() << "] 收到关门指令,开始关门..." << endl;
        elevator.switchState<ClosingState>(); // 切换到关门状态
    }

    void handleTimeout(Elevator& elevator) override {
        cout << "[" << getName() << "] 开门超时(3秒),自动关门..." << endl;
        elevator.switchState<ClosingState>(); // 切换到关门状态
    }
};

// --------------- 具体状态4:关门状态(ClosingState)---------------
class ClosingState : public ElevatorState {
public:
    string getName() const override { return "关门状态"; }

    void handleFloorPress(Elevator& elevator, int target_floor) override {
        if (target_floor == elevator.getCurrentFloor()) {
            cout << "[" << getName() << "] 当前已在" << target_floor << "楼,切换到待机状态" << endl;
            elevator.setTargetFloor(-1);
            elevator.switchState<IdleState>();
            return;
        }
        cout << "[" << getName() << "] 收到目标楼层" << target_floor << ",关门后运行..." << endl;
        elevator.setTargetFloor(target_floor);
        elevator.switchState<RunningState>(); // 切换到运行状态
    }

    void handleOpenPress(Elevator& elevator) override {
        cout << "[" << getName() << "] 收到开门指令,重新开门..." << endl;
        elevator.switchState<OpeningState>(); // 切换到开门状态
    }

    void handleClosePress(Elevator& elevator) override {
        cout << "[" << getName() << "] 已处于关门状态,无需操作" << endl;
    }

    void handleTimeout(Elevator& elevator) override {
        if (elevator.getTargetFloor() == -1) {
            cout << "[" << getName() << "] 关门超时,无目标楼层,切换到待机状态" << endl;
            elevator.switchState<IdleState>(); // 切换到待机
        } else {
            cout << "[" << getName() << "] 关门超时,有目标楼层" << elevator.getTargetFloor() << ",开始运行..." << endl;
            elevator.switchState<RunningState>(); // 切换到运行
        }
    }
};

// -------------------------- 测试代码(客户端) --------------------------
int main() {
    // 1. 创建电梯(智能指针自动管理内存)
    Elevator elevator;
    cout << "========================================\n";

    // 2. 模拟电梯操作流程
    elevator.pressFloor(3);    // 待机→运行
    elevator.timeout();        // 运行→开门
    elevator.timeout();        // 开门→关门
    elevator.pressFloor(5);    // 关门→运行
    elevator.pressOpen();      // 运行中开门(无效)
    elevator.timeout();        // 运行→开门
    elevator.pressClose();     // 开门→关门
    elevator.timeout();        // 关门→待机
    elevator.pressFloor(1);    // 待机→运行
    cout << "========================================\n";

    return 0; // 智能指针自动销毁所有对象
}

C++实现关键要点

  1. 抽象基类+多态ElevatorState定义纯虚函数接口,具体状态类继承并实现,环境类通过unique_ptr<ElevatorState>持有当前状态,多态调用行为,解耦环境与具体状态。
  2. 智能指针管理内存:用unique_ptr管理状态对象,自动创建和销毁,避免内存泄漏;虚析构函数确保子类析构被正确调用。
  3. 状态切换接口:环境类提供switchState模板方法,具体状态类通过该方法切换状态,无需直接操作current_state_指针,封装性更强。
  4. 上下文访问:环境类提供getter/setter方法,状态类可访问和修改电梯的楼层、目标楼层等上下文数据,无需直接暴露私有成员。
  5. 扩展性极强:新增状态(如“故障状态”)时,仅需创建新的子类继承ElevatorState并实现纯虚函数,修改相关状态的切换逻辑,环境类和客户端无需改动,完全符合“开闭原则”。
  6. 代码简洁优雅:继承+多态替代函数指针,STL和智能指针简化内存管理和状态切换,日志输出更清晰,类型安全更高。

状态模式核心总结(C vs C++)

对比维度C语言实现C++语言实现
接口定义结构体+函数指针抽象基类+纯虚函数(多态)
内存管理静态状态实例+环境类手动malloc/free智能指针(unique_ptr)自动管理,RAII原则
状态切换直接修改环境类的状态指针环境类提供switchState模板方法,封装切换逻辑
类型安全依赖手动指针操作,风险高编译期类型检查+多态,类型安全
封装性状态和环境的成员直接访问,封装性一般私有成员+getter/setter,封装性强
扩展性新增状态需定义结构体+函数指针,手动绑定新增状态仅需继承抽象基类,实现纯虚函数
代码可读性函数指针和全局状态实例,可读性一般类继承结构清晰,多态调用直观,可读性强

通用关键要点(跨语言)

设计原则

  • 单一职责原则:每个状态类仅负责自身的行为和切换逻辑,环境类仅负责上下文管理;
  • 开闭原则:新增状态无需修改现有代码,仅需新增状态类;
  • 依赖倒置原则:环境类依赖状态抽象,不依赖具体状态实现。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值