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 已完成
完成状态:工作流已完成,无法暂停

总结

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

相关推荐
狗头大军之江苏分军18 分钟前
《潮水漫过十七岁》开学了
后端
苏三说技术1 小时前
如何看待GPT-6在UP主众测中碾压夺冠?它是现在最强大模型吗?
后端
mldong1 小时前
一份 JSON,一条能跑的审批流:把报销流程送上工作流引擎
后端·架构
wno7041 小时前
Spring Boot WebFlux增删改查
java·spring boot·后端
Captaincc1 小时前
AI用量v0.1.11更新发布 新增 jusage doctor 诊断指令 托盘展示token 和余额 新增 AutoClaw 支持
前端·后端·vibecoding
aramae2 小时前
模拟实现strlen()函数 (C语言)
c语言·开发语言·后端
计算机魔术师3 小时前
德国Wiki被黑后两周,OpenAI终于把模型失控的账本摊开了
前端
kyriewen3 小时前
我让 AI 当面试官面了我一轮:第 3 个追问我就卡住了(附 10 道追问清单)
前端·面试·ai编程
IT_陈寒3 小时前
Python的GIL把我坑惨了,多线程跑得比单线程还慢
前端·人工智能·后端
分支预测失败3 小时前
RISC-V 时间子系统深度专题:mtime 访问路径、SBI 定时器与 Linux tickless 协同
后端