TypeScript设计模式:责任链模式

责任链模式(Chain of Responsibility Pattern)是一种行为设计模式,允许将请求沿处理者链传递,直到某个处理者处理请求或链结束为止。

设计模式原理

责任链模式通过构建一个处理者链,允许请求在链中传递,每个处理者决定是否处理请求或传递给下一个处理者。在工作流引擎中,责任链模式适合处理需要多级审批或条件判断的场景(如审批金额、验证权限),通过泛型节点确保类型安全,动态构建处理链。

责任链模式的结构

  1. Handler(处理者接口) :定义处理请求的方法和设置下一个处理者的方法。
  2. ConcreteHandler(具体处理者) :实现处理逻辑,决定是否处理或传递请求。
  3. Client(客户端) :通过 JSON 配置创建处理链并发起请求。

优点

  • 解耦性:请求发送者与处理者解耦,客户端无需知道具体处理者。
  • 灵活性:动态调整处理链顺序或添加新处理者。
  • 类型安全:结合泛型节点,确保请求和处理逻辑的参数类型匹配。
  • 可扩展性:新增处理者只需实现新节点,无需修改现有代码。

适用场景

  • 需要多级处理请求(如工作流中的审批、验证、日志记录)。
  • 处理者顺序或逻辑动态变化。
  • 希望通过声明式配置(如 JSON)定义处理链。

TypeScript 实现示例

以下示例在工作流引擎中使用泛型节点 GenericNode<T>,通过责任链模式实现审批流程。客户端通过 JSON 配置定义处理链(如初级审批 → 高级审批),每个节点决定是否处理请求或传递给下一个节点。

typescript 复制代码
// 节点类型枚举
enum NodeType {
    APPROVAL = 'approval',
    VALIDATION = 'validation',
    LOGGING = 'logging'
}

// JSON 节点配置接口
interface NodeConfigJson<T = any> {
    type: NodeType;
    params: T & { id: string };
}

// 请求参数类型
interface ApprovalRequest {
    amount: number;
    user: string;
}

// 节点参数类型
interface ApprovalParams { id: string; level: string; threshold: number }
interface ValidationParams { id: string; requiredRole: string }
interface LoggingParams { id: string; logLevel: string }

// 泛型节点接口(处理者接口)
interface WorkflowNode<T> {
    type: NodeType;
    params: T;
    setNext(next: WorkflowNode<any>): void;
    handle(request: ApprovalRequest): string;
    getDetails(): string;
}

// 泛型节点实现
class GenericNode<T> implements WorkflowNode<T> {
    private next: WorkflowNode<any> | null = null;

    constructor(public type: NodeType, public params: T) {}

    setNext(next: WorkflowNode<any>): void {
        this.next = next;
    }

    handle(request: ApprovalRequest): string {
        switch (this.type) {
            case NodeType.APPROVAL:
                const approvalParams = this.params as ApprovalParams;
                if (request.amount <= approvalParams.threshold) {
                    return `审批节点(ID: ${approvalParams.id}, 级别: ${approvalParams.level}):批准金额 ${request.amount}`;
                }
                return this.passToNext(request, `审批节点(ID: ${approvalParams.id}):金额 ${request.amount} 超出权限`);
            case NodeType.VALIDATION:
                const validationParams = this.params as ValidationParams;
                if (request.user === validationParams.requiredRole) {
                    return `验证节点(ID: ${validationParams.id}):用户 ${request.user} 权限验证通过`;
                }
                return this.passToNext(request, `验证节点(ID: ${validationParams.id}):用户 ${request.user} 权限不足`);
            case NodeType.LOGGING:
                const loggingParams = this.params as LoggingParams;
                const logMessage = `日志节点(ID: ${loggingParams.id}, 级别: ${loggingParams.logLevel}):记录请求 ${JSON.stringify(request)}`;
                return this.next ? `${logMessage}\n${this.next.handle(request)}` : logMessage;
            default:
                return `未知节点类型:${this.type}`;
        }
    }

    private passToNext(request: ApprovalRequest, message: string): string {
        if (this.next) {
            return `${message}\n${this.next.handle(request)}`;
        }
        return `${message}\n未处理:无后续节点`;
    }

    getDetails(): string {
        return `详情:${this.type} 节点,ID=${this.params.id}, 参数=${JSON.stringify(this.params)}`;
    }
}

// 工厂类:创建节点
class WorkflowNodeFactory {
    createNode<T>(config: NodeConfigJson<T>): WorkflowNode<T> {
        return new GenericNode<T>(config.type, config.params);
    }
}

// 客户端代码:构建处理链并处理请求
function processWorkflow(factory: WorkflowNodeFactory, nodes: NodeConfigJson[], request: ApprovalRequest) {
    const workflowNodes = nodes.map(config => factory.createNode(config));

    // 构建责任链
    for (let i = 0; i < workflowNodes.length - 1; i++) {
        workflowNodes[i].setNext(workflowNodes[i + 1]);
    }

    // 输出节点详情
    console.log("=== 责任链详情 ===");
    workflowNodes.forEach((node, index) => {
        console.log(`节点 ${index + 1} 详情:${node.getDetails()}`);
    });

    // 处理请求
    console.log("\n=== 处理请求 ===");
    const result = workflowNodes[0].handle(request);
    console.log(result);
}

// 测试代码
function main() {
    // JSON 配置:初级审批 → 高级审批 → 日志记录
    const workflowNodes: NodeConfigJson[] = [
        {
            type: NodeType.APPROVAL,
            params: { id: "APP001", level: "初级", threshold: 1000 }
        },
        {
            type: NodeType.APPROVAL,
            params: { id: "APP002", level: "高级", threshold: 5000 }
        },
        {
            type: NodeType.LOGGING,
            params: { id: "LOG001", logLevel: "INFO" }
        }
    ];

    // 测试请求
    const request1: ApprovalRequest = { amount: 800, user: "manager" };
    const request2: ApprovalRequest = { amount: 2000, user: "manager" };

    console.log("工作流:初级审批 → 高级审批 → 日志记录");
    const factory = new WorkflowNodeFactory();

    console.log("\n=== 测试请求1(金额800) ===");
    processWorkflow(factory, workflowNodes, request1);

    console.log("\n=== 测试请求2(金额2000) ===");
    processWorkflow(factory, workflowNodes, request2);
}

main();

运行结果

ini 复制代码
工作流:初级审批 → 高级审批 → 日志记录

=== 测试请求1(金额800) ===
=== 责任链详情 ===
节点 1 详情:详情:approval 节点,ID=APP001, 参数={"id":"APP001","level":"初级","threshold":1000}
节点 2 详情:详情:approval 节点,ID=APP002, 参数={"id":"APP002","level":"高级","threshold":5000}
节点 3 详情:详情:logging 节点,ID=LOG001, 参数={"id":"LOG001","logLevel":"INFO"}

=== 处理请求 ===
审批节点(ID: APP001, 级别: 初级):批准金额 800
日志节点(ID: LOG001, 级别: INFO):记录请求 {"amount":800,"user":"manager"}

=== 测试请求2(金额2000) ===
=== 责任链详情 ===
节点 1 详情:详情:approval 节点,ID=APP001, 参数={"id":"APP001","level":"初级","threshold":1000}
节点 2 详情:详情:approval 节点,ID=APP002, 参数={"id":"APP002","level":"高级","threshold":5000}
节点 3 详情:详情:logging 节点,ID=LOG001, 参数={"id":"LOG001","logLevel":"INFO"}

=== 处理请求 ===
审批节点(ID: APP001):金额 2000 超出权限
审批节点(ID: APP002, 级别: 高级):批准金额 2000
日志节点(ID: LOG001, 级别: INFO):记录请求 {"amount":2000,"user":"manager"}

总结

通过泛型节点 GenericNode<T>,责任链模式在工作流引擎中实现了请求的动态处理。客户端通过 JSON 配置定义处理链,节点根据条件处理请求或传递给下一个节点。泛型确保了类型安全,责任链模式提供了解耦性和灵活性,适合处理多级审批或验证的工作流场景。

相关推荐
苏三说技术3 小时前
为什么越来越多人用 Pi ? - 苏三说技术
后端
无糖可可果3 小时前
从零读懂一个 Next.js 全栈笔记应用
前端
Maxkim3 小时前
DeepSeek Harness 源码深度分析:像 VS Code 一样插件化的 Agent 框架
前端·架构
喜欢睡觉3 小时前
从零看懂一个 Next.js 笔记应用
前端
cindershade3 小时前
从零实现画布「双击创建节点」:一个 VueFlow 项目的交互全记录
前端
YHL3 小时前
🚀 SSE 服务器发送事件与 BFF 层实战
前端·后端
今日无bug3 小时前
HTML5 Canvas:从画图到游戏开发
前端·canvas
cindershade4 小时前
用 Web Workers 优化前端重计算任务:避免主线程卡顿的实战方案
前端
爱丶不疚4 小时前
搞不清 CommonJS 与 ESM,你是否也有这些疑问🤔
前端·node.js
星火10244 小时前
【LangChain4j系列05】RAG 检索增强生成完整指南
人工智能·后端