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