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 配置定义处理链,节点根据条件处理请求或传递给下一个节点。泛型确保了类型安全,责任链模式提供了解耦性和灵活性,适合处理多级审批或验证的工作流场景。

相关推荐
一枚前端小能手1 小时前
📋 前端复制那点事 - 5个实用技巧让你的复制功能更完美
前端·javascript
三小河1 小时前
解决vite环境下调用获取二进制文件流 部分文件报错 (failed)net::ERR_INVALID_HTTP_RESPONSE)
前端
好好好明天会更好1 小时前
pinia从定义到运用
前端·vue.js
代码小学僧1 小时前
Vite 项目最简单方法解决部署后 Failed to fetch dynamically imported Error问题
前端·vue.js·vite
RoyLin1 小时前
TypeScript设计模式:装饰器模式
前端·后端·typescript
Java中文社群2 小时前
有点意思!Java8后最有用新特性排行榜!
java·后端·面试
代码匠心2 小时前
从零开始学Flink:数据源
java·大数据·后端·flink
掘金一周2 小时前
Flutter Riverpod 3.0 发布,大规模重构下的全新状态管理框架 | 掘金一周 9.18
前端·人工智能·后端
一涯2 小时前
页面出现空白区域
前端