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 分钟前
【开题答辩过程】以《基于Android的出租车运行监测系统设计与实现》为例,不知道这个选题怎么做的,不知道这个选题怎么开题答辩的可以进来看看
java·后端·vue
三七吃山漆7 分钟前
攻防世界——wife_wife
前端·javascript·web安全·网络安全·ctf
m0_740043739 分钟前
SpringBoot05-配置文件-热加载/日志框架slf4j/接口文档工具Swagger/Knife4j
java·spring boot·后端·log4j
用户479492835691511 分钟前
面试官问"try-catch影响性能吗",我用数据打脸
前端·javascript·面试
GISer_Jing34 分钟前
前端营销技术实战:数据+AI实战指南
前端·javascript·人工智能
GIS之路1 小时前
使用命令行工具 ogr2ogr 将 CSV 转换为 Shp 数据(二)
前端
嘉琪0011 小时前
Vue3+JS 高级前端面试题
开发语言·前端·javascript
招风的黑耳1 小时前
我用SpringBoot撸了一个智慧水务监控平台
java·spring boot·后端
Miss_Chenzr1 小时前
Springboot优卖电商系统s7zmj(程序+源码+数据库+调试部署+开发环境)带论文文档1万字以上,文末可获取,系统界面在最后面。
数据库·spring boot·后端
期待のcode1 小时前
Springboot核心构建插件
java·spring boot·后端