TypeScript设计模式:状态模式

状态模式(State Pattern)是一种行为型设计模式,允许对象在内部状态变化时改变其行为,仿佛对象改变了其类。它通过将状态封装为独立的状态类,并将行为委托给当前状态对象,从而实现灵活的状态切换和行为管理。

设计模式原理

状态模式的核心是将对象的状态行为封装到独立的状态类中,上下文对象(Context)通过持有当前状态对象,委托行为给状态类,从而在状态切换时自动改变行为。

结构

  • 状态接口(State):定义状态的行为接口。
  • 具体状态(ConcreteState):实现状态接口,定义特定状态的行为。
  • 上下文(Context):持有当前状态对象,提供状态切换和行为委托的方法。

优点

  • 单一职责:每个状态类负责单一状态的行为,代码清晰。
  • 开闭原则:新增状态只需添加新状态类,无需修改上下文。
  • 状态隔离:状态相关逻辑封装在状态类中,减少条件分支。
  • 灵活切换:动态更改状态,行为随之变化。

缺点

  • 类爆炸:状态较多时,可能导致状态类数量增加。
  • 复杂初始化:多状态系统需小心管理状态转换逻辑。
  • 状态依赖:状态间可能存在复杂依赖,需设计转换规则。
  • 性能开销:频繁切换状态可能增加对象创建成本。

适用场景

  • 状态驱动行为:对象行为随状态变化,如工作流、任务调度。
  • 复杂条件逻辑:替代大量if-else分支,如订单处理、任务流。
  • 状态机:如协议状态管理、UI组件状态。
  • 工作流系统:如任务执行、流程自动化。

TypeScript 实现示例

我们实现一个工作流系统,从模板生成实例,通过状态模式管理实例状态(初始化、运行中、暂停、失败、完成)。代码使用TypeScript确保类型安全。

项目结构

arduino 复制代码
workflow-instance/
├── src/
│   ├── state.ts         // 状态接口和具体状态
│   ├── instance.ts      // 上下文(工作流实例)
│   ├── template.ts      // 工作流模板
│   ├── main.ts         // 执行示例
├── tsconfig.json
├── package.json

1. 安装依赖

bash 复制代码
npm init -y
npm install typescript @types/node
npx tsc --init

配置 tsconfig.json

json 复制代码
{
  "compilerOptions": {
    "target": "ES2020",
    "module": "ESNext",
    "strict": true,
    "moduleResolution": "node"
  }
}

2. 定义状态接口和具体状态 (state.ts)

typescript 复制代码
export interface WorkflowState {
  start(instance: WorkflowInstance): void;
  pause(instance: WorkflowInstance): void;
  resume(instance: WorkflowInstance): void;
  fail(instance: WorkflowInstance, error: string): void;
  complete(instance: WorkflowInstance): void;
}

export class InitializedState implements WorkflowState {
  start(instance: WorkflowInstance): void {
    instance.setState(new RunningState());
    console.log(`初始化状态:工作流实例 ${instance.getInstanceId()} 已开始运行`);
  }

  pause(_instance: WorkflowInstance): void {
    console.log('初始化状态:无法暂停,请先开始运行');
  }

  resume(_instance: WorkflowInstance): void {
    console.log('初始化状态:无法恢复,请先开始运行');
  }

  fail(_instance: WorkflowInstance, error: string): void {
    console.log(`初始化状态:无法失败,错误:${error}`);
  }

  complete(_instance: WorkflowInstance): void {
    console.log('初始化状态:无法完成,请先开始运行');
  }
}

export class RunningState implements WorkflowState {
  start(_instance: WorkflowInstance): void {
    console.log('运行中状态:工作流已在运行,无需重复启动');
  }

  pause(instance: WorkflowInstance): void {
    instance.setState(new PausedState());
    console.log(`运行中状态:工作流实例 ${instance.getInstanceId()} 已暂停`);
  }

  resume(_instance: WorkflowInstance): void {
    console.log('运行中状态:工作流已在运行,无需恢复');
  }

  fail(instance: WorkflowInstance, error: string): void {
    instance.setState(new FailedState(error));
    console.log(`运行中状态:工作流实例 ${instance.getInstanceId()} 失败,错误:${error}`);
  }

  complete(instance: WorkflowInstance): void {
    instance.setState(new CompletedState());
    console.log(`运行中状态:工作流实例 ${instance.getInstanceId()} 已完成`);
  }
}

export class PausedState implements WorkflowState {
  start(_instance: WorkflowInstance): void {
    console.log('暂停状态:无法直接启动,请先恢复');
  }

  pause(_instance: WorkflowInstance): void {
    console.log('暂停状态:工作流已暂停,无需重复暂停');
  }

  resume(instance: WorkflowInstance): void {
    instance.setState(new RunningState());
    console.log(`暂停状态:工作流实例 ${instance.getInstanceId()} 已恢复运行`);
  }

  fail(instance: WorkflowInstance, error: string): void {
    instance.setState(new FailedState(error));
    console.log(`暂停状态:工作流实例 ${instance.getInstanceId()} 失败,错误:${error}`);
  }

  complete(_instance: WorkflowInstance): void {
    console.log('暂停状态:无法直接完成,请先恢复运行');
  }
}

export class FailedState implements WorkflowState {
  constructor(private error: string) {}

  start(_instance: WorkflowInstance): void {
    console.log('失败状态:工作流已失败,无法启动');
  }

  pause(_instance: WorkflowInstance): void {
    console.log('失败状态:工作流已失败,无法暂停');
  }

  resume(_instance: WorkflowInstance): void {
    console.log('失败状态:工作流已失败,无法恢复');
  }

  fail(_instance: WorkflowInstance, error: string): void {
    console.log(`失败状态:工作流已失败,当前错误:${this.error},新错误:${error}`);
  }

  complete(_instance: WorkflowInstance): void {
    console.log('失败状态:工作流已失败,无法完成');
  }
}

export class CompletedState implements WorkflowState {
  start(_instance: WorkflowInstance): void {
    console.log('完成状态:工作流已完成,无法重新启动');
  }

  pause(_instance: WorkflowInstance): void {
    console.log('完成状态:工作流已完成,无法暂停');
  }

  resume(_instance: WorkflowInstance): void {
    console.log('完成状态:工作流已完成,无法恢复');
  }

  fail(_instance: WorkflowInstance, error: string): void {
    console.log(`完成状态:工作流已完成,无法失败,错误:${error}`);
  }

  complete(_instance: WorkflowInstance): void {
    console.log('完成状态:工作流已完成,无需重复完成');
  }
}

3. 实现工作流模板 (template.ts)

typescript 复制代码
import { WorkflowInstance } from './instance';

export class WorkflowTemplate {
  private templateId: string;
  private name: string;

  constructor(id: string, name: string) {
    this.templateId = id;
    this.name = name;
    console.log(`工作流模板 ${name} (ID: ${id}) 已创建`);
  }

  createInstance(instanceId: string): WorkflowInstance {
    const instance = new WorkflowInstance(instanceId, this);
    console.log(`从模板 ${this.name} 创建实例 ${instanceId}`);
    return instance;
  }

  getTemplateId(): string {
    return this.templateId;
  }

  getName(): string {
    return this.name;
  }
}

4. 实现上下文 (instance.ts)

typescript 复制代码
import { WorkflowState, InitializedState } from './state';
import { WorkflowTemplate } from './template';

export class WorkflowInstance {
  private state: WorkflowState;
  private instanceId: string;
  private template: WorkflowTemplate;

  constructor(instanceId: string, template: WorkflowTemplate) {
    this.instanceId = instanceId;
    this.template = template;
    this.state = new InitializedState();
    console.log(`工作流实例 ${instanceId} 已初始化`);
  }

  setState(state: WorkflowState): void {
    this.state = state;
  }

  getInstanceId(): string {
    return this.instanceId;
  }

  getTemplate(): WorkflowTemplate {
    return this.template;
  }

  start(): void {
    this.state.start(this);
  }

  pause(): void {
    this.state.pause(this);
  }

  resume(): void {
    this.state.resume(this);
  }

  fail(error: string): void {
    this.state.fail(this, error);
  }

  complete(): void {
    this.state.complete(this);
  }
}

5. 运行示例 (main.ts)

typescript 复制代码
import { WorkflowTemplate } from './template';

// 创建模板
const template = new WorkflowTemplate('T001', '报告生成工作流');

// 从模板生成实例
const instance = template.createInstance('INST_001');

// 测试状态转换
instance.start();
instance.pause();
instance.resume();
instance.fail('数据库连接错误');
instance.complete(); // 应失败

// 创建另一个实例并测试
const instance2 = template.createInstance('INST_002');
instance2.start();
instance2.complete();
instance2.pause(); // 应失败

6. 编译与运行

bash 复制代码
npx tsc
node dist/main.js

运行后,控制台输出类似:

scss 复制代码
工作流模板 报告生成工作流 (ID: T001) 已创建
从模板 报告生成工作流 创建实例 INST_001
工作流实例 INST_001 已初始化
初始化状态:工作流实例 INST_001 已开始运行
运行中状态:工作流实例 INST_001 已暂停
暂停状态:工作流实例 INST_001 已恢复运行
运行中状态:工作流实例 INST_001 失败,错误:数据库连接错误
失败状态:工作流已失败,无法完成
从模板 报告生成工作流 创建实例 INST_002
工作流实例 INST_002 已初始化
初始化状态:工作流实例 INST_002 已开始运行
运行中状态:工作流实例 INST_002 已完成
完成状态:工作流已完成,无法暂停

总结

状态模式的优点在于其单一职责、开闭原则、状态隔离和灵活切换。每个状态类负责单一状态的行为,代码清晰;新增状态只需添加新状态类,无需修改上下文;状态逻辑封装在状态类中,减少条件分支;动态切换状态,行为随之变化。该模式特别适用于状态驱动行为、复杂条件逻辑、状态机和工作流系统场景,如工作流管理(任务执行、流程自动化)、游戏角色状态、订单处理和协议状态管理。

相关推荐
想用offer打牌26 分钟前
MCP (Model Context Protocol) 技术理解 - 第二篇
后端·aigc·mcp
崔庆才丨静觅1 小时前
hCaptcha 验证码图像识别 API 对接教程
前端
passerby60612 小时前
完成前端时间处理的另一块版图
前端·github·web components
KYGALYX2 小时前
服务异步通信
开发语言·后端·微服务·ruby
掘了2 小时前
「2025 年终总结」在所有失去的人中,我最怀念我自己
前端·后端·年终总结
崔庆才丨静觅2 小时前
实用免费的 Short URL 短链接 API 对接说明
前端
崔庆才丨静觅2 小时前
5分钟快速搭建 AI 平台并用它赚钱!
前端
爬山算法2 小时前
Hibernate(90)如何在故障注入测试中使用Hibernate?
java·后端·hibernate
崔庆才丨静觅3 小时前
比官方便宜一半以上!Midjourney API 申请及使用
前端
Moment3 小时前
富文本编辑器在 AI 时代为什么这么受欢迎
前端·javascript·后端