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

总结

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

相关推荐
RoyLin2 小时前
TypeScript设计模式:观察者模式
前端·后端·typescript
干就完了12 小时前
js对象常用方法都在这,使用时想不到?不存在的
前端·javascript
艾小码2 小时前
还在硬邦邦跳转页面?Vue这3招让应用丝滑如德芙!
前端·javascript·vue.js
RoyLin2 小时前
TypeScript设计模式:备忘录模式
前端·后端·typescript
阿笑带你学前端2 小时前
Flutter本地通知系统:记账提醒的深度实现
前端·flutter
白衣鸽子2 小时前
PageHelper:分页陷阱避免与最佳实践
后端
BingoGo2 小时前
PHP 和 Elasticsearch:给你的应用加个强力搜索引擎
后端·php
泉城老铁2 小时前
Spring Boot对接抖音获取H5直播链接详细指南
spring boot·后端·架构
武子康2 小时前
大数据-101 Spark Streaming 有状态转换详解:窗口操作与状态跟踪实战 附多案例代码
大数据·后端·spark