模式组合应用-责任链模式

47 阅读17分钟

写在前面

Hello,我是易元,这篇文章是我学习设计模式时的笔记和心得体会。如果其中有错误,欢迎大家留言指正!


责任链模式

定义

行为型设计模式, 旨在避免请求发送者与接收者之间耦合过紧, 通过将多个对象组成一条链, 并沿着这条链传递请求, 直到有一个对象处理它为止。

角色

  • 抽象处理者: 定义一个处理请求的接口, 通常包含一个处理请求的方法和一个设置下一个处理者的方法。
  • 具体处理者: 实现抽象处理者接口, 处理它所负责的请求, 如果不能处理, 则将请求转发给下一个处理者。

使用时主要思考点

  1. 构建链时, 要确保处理者之间不会形成循环引用, 避免导致无限循环。
  2. 每个处理者应该只关注自己能处理的特定请求类型或处理逻辑, 避免一个处理者承担过多的职责。

责任链模式+命令模式

命令模式

行为型设计模式, 将请求本身封装成一个对象, 这个对象包含了执行请求所需的所有消息, 包括接收者和动作。

案例

在多租户SaaS系统的登录模块中, 实现以下校验步骤及流程: 账号密码验证、租户信息获取、Token生成等。每个步骤都可能因为不同的业务需求而变化, 使用模式组合进行实现。

模式职责

  • 命令模式: 将每个登录步骤(如账号验证、租户信息获取等)封装为独立的命令对象, 使它们可以独立变化和复用。
  • 责任链模式: 将多个命令对象组织成一条处理链, 实现登录流程的自动传递和执行顺序控制。

代码示例

LoginContext上下文
public class LoginContext {

    private String username;

    private String password;

    private String appPackageName;

    // 账号校验状态
    private boolean accountValid = false;

    private String tenantId;

    private String tenantName;

    private String token;

    private boolean success = false;

    private String errorMessage;

    public LoginContext(String username, String password, String appPackageName) {
        this.username = username;
        this.password = password;
        this.appPackageName = appPackageName;
    }

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }

    public String getAppPackageName() {
        return appPackageName;
    }

    public void setAppPackageName(String appPackageName) {
        this.appPackageName = appPackageName;
    }

    public boolean isAccountValid() {
        return accountValid;
    }

    public void setAccountValid(boolean accountValid) {
        this.accountValid = accountValid;
    }

    public String getTenantId() {
        return tenantId;
    }

    public void setTenantId(String tenantId) {
        this.tenantId = tenantId;
    }

    public String getTenantName() {
        return tenantName;
    }

    public void setTenantName(String tenantName) {
        this.tenantName = tenantName;
    }

    public String getToken() {
        return token;
    }

    public void setToken(String token) {
        this.token = token;
    }

    public boolean isSuccess() {
        return success;
    }

    public void setSuccess(boolean success) {
        this.success = success;
    }

    public String getErrorMessage() {
        return errorMessage;
    }

    public void setErrorMessage(String errorMessage) {
        this.errorMessage = errorMessage;
    }

    @Override
    public String toString() {
        return "[" +
                "username='" + username + ''' +
                ", password='" + password + ''' +
                ", appPackageName='" + appPackageName + ''' +
                ", accountValid=" + accountValid +
                ", tenantId='" + tenantId + ''' +
                ", tenantName='" + tenantName + ''' +
                ", token='" + token + ''' +
                ", success=" + success +
                ", errorMessage='" + errorMessage + ''' +
                ']';
    }
}
  • 封装登录过程的所有输入参数和输出结果, 提供命令间接数据传递的媒介, 贯穿整个责任链的状态容器。
LoginCommand 接口
public interface LoginCommand {

    void setNext(LoginCommand nextCommand);

    boolean execute(LoginContext context);

}
  • 整个模式组合的核心接口, 同时承担命令模式和责任链模式的双重角色。
  • 作为命令模式中的抽象命令, 定义统一的命令执行方法 boolean execute(LoginContext context) 命令模式的核心方法, 执行具体业务逻辑。
  • 作为责任链模式中的抽象处理者, void setNext(LoginCommand nextCommand) 用于构建链式结构。
AbstractLoginCommand抽象类

public abstract class AbstractLoginCommand implements LoginCommand {

    protected LoginCommand nextCommand;

    @Override
    public void setNext(LoginCommand nextCommand) {
        this.nextCommand = nextCommand;
    }

    @Override
    public boolean execute(LoginContext context) {

        System.out.println("--- 执行命令: " + this.getClass().getSimpleName() + " ---");

        boolean result = this.process(context);

        if (!result) {
            System.out.println("❌ " + this.getClass().getSimpleName() + " 失败, 流程终止。");
            return false;
        }

        if (nextCommand != null) {
            return nextCommand.execute(context);
        }

        return true;
    }

    protected abstract boolean process(LoginContext context);
}
  • 提供责任链的默认实现, 处理链式传递的通用逻辑, 定义模板方法让子类专注于具体业务实现。
  • protected LoginCommand nextCommand 维护链中的下一个处理器。
  • void setNext(LoginCommand nextCommand) 设置下一个处理者。
  • boolean execute(LoginContext context) 模板方法, 执行固定流程逻辑。
  • abstract boolean process(LoginContext context) 子类实现具体业务逻辑。
具体命令类
public class AccountValidationCommand extends AbstractLoginCommand {

    @Override
    protected boolean process(LoginContext context) {

        System.out.println("正在校验账号: " + context.getUsername());

        if (context.getUsername().equals("admin") && context.getPassword().equals("123456")) {
            context.setAccountValid(true);
            System.out.println("√ 账号校验成功。");
            return true;
        }

        else if (context.getUsername().equals("guest") && context.getPassword().equals("guest")) {
            context.setAccountValid(true);
            System.out.println("√ 账号校验成功(访客)。");
            return true;
        }
        else {
            context.setErrorMessage("用户名或密码错误。");
            return false;
        }

    }
}

public class TenantInfoCommand extends AbstractLoginCommand {

    @Override
    protected boolean process(LoginContext context) {
        if (context.isAccountValid()) {
            context.setErrorMessage("账号未校验通过。");
            return false;
        }

        System.out.println("正在根据包名获取租户信息: " + context.getAppPackageName());

        String packageName = context.getAppPackageName();
        if (packageName.equals("com.app.enterprise")) {
            context.setTenantId("T001");
            context.setTenantName("企业版租户");
            System.out.println("√ 租户信息获取成功: T001 - 企业版租户。");
            return true;
        }
        else if (packageName.equals("com.app.basic")) {
            context.setTenantId("T002");
            context.setTenantName("基础版租户");
            System.out.println("√ 租户信息获取成功: T002 - 基础版租户。");
            return true;
        }
        else {
            context.setErrorMessage("APP包名无效或未注册租户。");
            return false;
        }
    }

}

public class TokenGenerationCommand extends AbstractLoginCommand {

    @Override
    protected boolean process(LoginContext context) {

        if (context.getTenantId() == null || context.getTenantId().isEmpty()) {
            context.setErrorMessage("未获取到租户信息。");
            return false;
        }

        System.out.println("正在为用户 [" + context.getUsername() + "] 和租户 [" + context.getTenantId() + "] 生成Token...");
        String rawToken = context.getUsername() + ":" + context.getTenantId() + ":" + UUID.randomUUID().toString();
        String token = "JWT_" + rawToken.hashCode();

        context.setToken(token);
        context.setSuccess(true);
        System.out.println("√ Token生成成功。");
        return true;
    }
}
  • AccountValidationCommand 负责账号密码验证, 验证用户凭证的正确性, 设置账号验证状态到上下文, 提供明确的成功/失败反馈。
  • TenantInfoCommand 多租户中的租户信息识别, 校验密码账号验证是否通过, 根据应用包名识别租户类型, 将租户信息设置到上下文中。
  • TokenGenerationCommand 登录最终流程, 生成访问令牌, 验证租户信息是否存在, 生成访问令牌。
测试类
public class ChainTest {

    @Test
    public void test_login() {

        LoginCommand accountValidation = new AccountValidationCommand();
        LoginCommand tenantInfo = new TenantInfoCommand();
        LoginCommand tokenGeneration = new TokenGenerationCommand();

        accountValidation.setNext(tenantInfo);
        tenantInfo.setNext(tokenGeneration);

        System.out.println("----------- 成功登录 ---------");
        LoginContext context1 = new LoginContext("admin""123456""com.app.enterprise");
        boolean result1 = accountValidation.execute(context1);
        System.out.println("流程结果: " + (result1 ? "成功" : "失败") + ", 最终状态: " + context1);

        System.out.println("\n----------- 账号校验失败 ---------");
        LoginContext context2 = new LoginContext("baduser""wrongpass""com.app.enterprise");
        boolean result2 = accountValidation.execute(context2);
        System.out.println("流程结果: " + (result2 ? "成功" : "失败") + ", 最终状态: " + context2);

        System.out.println("\n----------- 租户获取失败 ---------");
        LoginContext context3 = new LoginContext("guest""guest""com.app.unknown");
        boolean result3 = accountValidation.execute(context3);
        System.out.println("流程结果: " + (result3 ? "成功" : "失败") + ", 最终状态: " + context3);

    }

}
执行结果
----------- 成功登录 ---------
--- 执行命令: AccountValidationCommand ---
正在校验账号: admin
√ 账号校验成功。
--- 执行命令: TenantInfoCommand ---
❌ TenantInfoCommand 失败, 流程终止。
流程结果: 失败, 最终状态: [username='admin', password='123456', appPackageName='com.app.enterprise', accountValid=true, tenantId='null', tenantName='null', token='null', success=false, errorMessage='账号未校验通过。']

----------- 账号校验失败 ---------
--- 执行命令: AccountValidationCommand ---
正在校验账号: baduser
❌ AccountValidationCommand 失败, 流程终止。
流程结果: 失败, 最终状态: [username='baduser', password='wrongpass', appPackageName='com.app.enterprise', accountValid=false, tenantId='null', tenantName='null', token='null', success=false, errorMessage='用户名或密码错误。']

----------- 租户获取失败 ---------
--- 执行命令: AccountValidationCommand ---
正在校验账号: guest
√ 账号校验成功(访客)。
--- 执行命令: TenantInfoCommand ---
❌ TenantInfoCommand 失败, 流程终止。
流程结果: 失败, 最终状态: [username='guest', password='guest', appPackageName='com.app.unknown', accountValid=true, tenantId='null', tenantName='null', token='null', success=false, errorMessage='账号未校验通过。']

Process finished with exit code 0

组合优势

  • 命令模式封装请求, 使调用者与执行者解耦, 责任链模式管理传递, 使发送者与接收者链解耦。
  • 动态增删或调整责任链中的处理节点, 甚至动态改变处理流程。
  • 命令对象专注于做什么, 责任链节点专注于谁来做及是否向下传递。

责任链模式+策略模式

策略模式

行为型设计模式, 定义一系列算法, 将每个算法封装起来, 并使得它们可以相互替换。

案例

在一个电商系统中, 用户提交订单后, 需要根据多种规则计算最终的折扣金额。折扣规则包含: 新用户折扣、会员登陆折扣、满减活动、优惠券折扣等。每种折扣规则都有其独立的计算逻辑, 并且这些规则可能需要按特定顺序进行评估, 直到某个规则被应用或所有规则评估完毕。

模式职责

  • 责任链模式: 负责按照顺序依次应用不同的折扣策略, 每个处理者(即折扣计算器)在链中判断是否满足其折扣条件, 如果满足则应用折扣并可能终止链的传递。
  • 策略模式: 每种具体的折扣计算逻辑封装成一个独立的策略, 每个策略都实现了统一的折扣计算接口, 使得责任链中的处理者可以灵活的选择和调用不同的折扣策略来计算折扣。

代码示例

策略模式-抽象策略
public interface DiscountStrategy {

    double calculateDiscount(Order order);

}
  • 策略模式的抽象策略角色, 定义了一个统一的入口 calculateDiscount(Order order), 使得所有具体的折扣方法都遵循相同的规范, 接收 Order 对象, 返回计算出的折扣金额。
策略模式-具体策略
public class CouponDiscountStrategy implements DiscountStrategy {

    @Override
    public double calculateDiscount(Order order) {

        if (order.getCouponCode() != null && !order.getCouponCode().isEmpty()) {
            if (order.getOriginalPrice() >= 100 && "SAVE20".equals(order.getCouponCode())) {
                order.addAppliedDiscountInfo("优惠券折扣(满100减20)");
                System.out.println("应用优惠券折扣: 优惠 20.00 元");
                return 20.0;
            }
        }

        return 0;
    }
}

public class NewUserDiscountStrategy implements DiscountStrategy {

    @Override
    public double calculateDiscount(Order order) {

        if (order.isNewUser()) {
            double discountAmount = order.getOriginalPrice() * 0.1;
            order.addAppliedDiscountInfo("新用户折扣(10%)");
            System.out.println("应用新用户折扣: 优惠 " + String.format("%.2f", discountAmount) + "元。");
            return discountAmount;
        }

        return 0;
    }
}

public class SuperVipMemberDiscountStrategy implements DiscountStrategy {

    @Override
    public double calculateDiscount(Order order) {
        if (order.getMemberLevel() == 2) {
            double discountAmount = order.getOriginalPrice() * 0.15;
            order.addAppliedDiscountInfo("SVIP会员折扣(15%)");
            System.out.println("应用SVIP会员折扣: 优惠 " + String.format("%.2f", discountAmount) + "元。");
            return discountAmount;
        }

        return 0;
    }
}

public class VipMemberDiscountStrategy implements DiscountStrategy {

    @Override
    public double calculateDiscount(Order order) {
        if (order.getMemberLevel() == 1) {
            double discountAmount = order.getOriginalPrice() * 0.05;
            order.addAppliedDiscountInfo("VIP会员折扣(5%)");
            System.out.println(String.format("应用VIP会员折扣: 优惠 %.2f 元。", discountAmount));
            return discountAmount;
        }

        return 0;
    }
}
  • 具体的算法实现者, 分别实现了 满减策略、新用户折扣策略、SVIP会员折扣策略、VIP会员折扣策略。
责任链模式-抽象处理者/策略模式-上下文
public abstract class DiscountHandler {

    protected DiscountHandler nextHandler;

    protected DiscountStrategy strategy;

    public DiscountHandler(DiscountStrategy strategy) {
        this.strategy = strategy;
    }

    public void setNextHandler(DiscountHandler nextHandler) {
        this.nextHandler = nextHandler;
    }

    public void handleDiscount(Order order) {
        double discount = strategy.calculateDiscount(order);
        if (discount > 0) {
            order.setFinalPrice(order.getFinalPrice() - discount);
            System.out.println("当前订单最终价格变为: " + String.format("%.2f", order.getFinalPrice()) + "元。");
        }

        if (nextHandler != null) {
            nextHandler.handleDiscount(order);
        }
    }

}
  • 责任链模式的核心骨架, 也算策略模式的上下文角色
  • 持有 nextHandler 引用, 负责链的构建和传递, 持有 strategy 引用, 负责调用具体的折扣计算逻辑。
  • handleDiscount 方法是模板方法, 先执行当前策略的计算, 更新订单价格, 然后无条件地将请求传递给下一个处理者。
责任链模式-具体处理者

public class CouponDiscountHandler extends DiscountHandler {

    public CouponDiscountHandler(DiscountStrategy strategy) {
        super(strategy);
    }
}

public class MemberLevelDiscountHandler extends DiscountHandler {

    public MemberLevelDiscountHandler(DiscountStrategy strategy) {
        super(strategy);
    }

    @Override
    public void handleDiscount(Order order) {
        DiscountStrategy currentStrategy = null;

        if (order.getMemberLevel() == 1) {
            currentStrategy = new VipMemberDiscountStrategy();
        }
        else if (order.getMemberLevel() == 2) {
            currentStrategy = new SuperVipMemberDiscountStrategy();
        }
        if (currentStrategy != null) {
            double discount = currentStrategy.calculateDiscount(order);
            if (discount > 0) {
                order.setFinalPrice(order.getFinalPrice() - discount);
                System.out.println("当前订单最终价格变为: " + String.format("%.2f", order.getFinalPrice()) + "元。");
            }
        }

        if (nextHandler != null) {
            nextHandler.handleDiscount(order);
        }
    }
}

public class NewUserDiscountHandler extends DiscountHandler {

    public NewUserDiscountHandler(NewUserDiscountStrategy strategy) {
        super(strategy);
    }
}
  • 责任链的节点, 通过构造函数注入一个具体的 DiscountStrategy 对象, 从而将特定的折扣算法与责任链上的特定位置绑定。
  • MemberLevelDiscountHandler 重写了 handleDiscount 方法, 内部根据 order.getMemberLevel() 动态实例化 VipMemberDiscountStrategySuperVipMemberDiscountStrategy, 使得一个处理者能够根据上下文条件选择最合适的算法。
测试类
public class ChainOfStrategyTest {

    @Test
    public void test_order() {
        NewUserDiscountHandler newUserHandler = new NewUserDiscountHandler(new NewUserDiscountStrategy());
        MemberLevelDiscountHandler memberLevelHandler = new MemberLevelDiscountHandler(null);
        CouponDiscountHandler couponHandler = new CouponDiscountHandler(new CouponDiscountStrategy());

        newUserHandler.setNextHandler(memberLevelHandler);
        memberLevelHandler.setNextHandler(couponHandler);

        System.out.println("\n--- 新用户订单 ---");
        Order order1 = new Order("user_new_001"120.0true0null);
        System.out.println("处理订单: " + order1);
        newUserHandler.handleDiscount(order1);
        System.out.println("最终订单: " + order1);

        System.out.println("\n--- VIP会员订单 ---");
        Order order2 = new Order("user_vip_002"200.0false1null);
        System.out.println("处理订单: " + order2);
        newUserHandler.handleDiscount(order2);
        System.out.println("最终订单: " + order2);

        System.out.println("\n--- SVIP会员订单 ---");
        Order order3 = new Order("user_svip_003"300.0false2"SAVE20");
        System.out.println("处理订单: " + order3.getUserId());
        newUserHandler.handleDiscount(order3);
        System.out.println("最终订单: " + order3);
    }

}
执行结果
--- 新用户订单 ---
处理订单: 订单 [用户ID: user_new_001, 原始价格: 120.00, 最终价格: 120.00, 已应用折扣: 无]
应用新用户折扣: 优惠 12.00元。
当前订单最终价格变为: 108.00元。
最终订单: 订单 [用户ID: user_new_001, 原始价格: 120.00, 最终价格: 108.00, 已应用折扣: 新用户折扣(10%)]

--- VIP会员订单 ---
处理订单: 订单 [用户ID: user_vip_002, 原始价格: 200.00, 最终价格: 200.00, 已应用折扣: 无]
应用VIP会员折扣: 优惠 10.00 元。
当前订单最终价格变为: 190.00元。
最终订单: 订单 [用户ID: user_vip_002, 原始价格: 200.00, 最终价格: 190.00, 已应用折扣: VIP会员折扣(5%)]

--- SVIP会员订单 ---
处理订单: user_svip_003
应用SVIP会员折扣: 优惠 45.00元。
当前订单最终价格变为: 255.00元。
应用优惠券折扣: 优惠 20.00 元
当前订单最终价格变为: 235.00元。
最终订单: 订单 [用户ID: user_svip_003, 原始价格: 300.00, 最终价格: 235.00, 已应用折扣: SVIP会员折扣(15%); 优惠券折扣(满100减20)]

Process finished with exit code 0

组合优势

  • 通过在责任链中添加逻辑, 可以轻松实现叠加折扣或互斥折扣。
  • 折扣计算的具体逻辑(策略)与折扣的应用流程(责任链)分离。责任链处理者不需要知道折扣计算逻辑, 只需要调用 currentStrategy.calculateDiscount

责任链模式+模板方法模式

模板方法模式

行为型设计模式, 在一个方法中定义一个算法的骨架, 将一些步骤延迟到子类中。模板方法使得子类可以在不改变算法结构的情况下, 重新定义算法的某些特定步骤。

案例

在一个数据分析系统中, 需要对原始数据进行一系列的标准化处理, 例如数据清洗、格式转换、数据校验、数据加密等。这些处理步骤的顺序是固定的, 但每个步骤的具体实现可能因数据源或业务需求而变化。同时, 某些处理步骤可能需要根据数据内容或处理结果决定是否继续进行后续处理。

模式职责

  • 责任链模式: 将不同的数据处理步骤串联起来, 形成一个数据处理管道, 每个处理者代表一个特定的数据处理环节, 并决定是否将处理后的数据传递给链中的下一个处理者, 使得数据可以按顺序经过一系列处理, 并且可以根据处理结果灵活地中断或继续。
  • 模板方法模式: 在每个责任链的具体处理者内部, 使用模板方法模式来定义该处理环节的通用处理流程。

代码示例

RawData(上下文)
public class RawData {

    private String content;

    private boolean isValid = true;

    private String processingLog = "";

    public RawData(String content) {
        this.content = content;
    }

    public String getContent() {
        return content;
    }

    public boolean isValid() {
        return isValid;
    }

    public String getProcessingLog() {
        return processingLog;
    }

    public void setContent(String content) {
        this.content = content;
    }

    public void setValid(boolean valid) {
        isValid = valid;
    }

    public void addProcessingLog(String log) {
        if (!this.processingLog.isEmpty()) {
            this.processingLog += " | ";
        }
        this.processingLog += log;
    }

    @Override
    public String toString() {
        return "原始数据 [内容: "" + content + "", 有效: " + isValid + ", 日志: " + processingLog + "]";
    }

}
  • 封装了待处理的原始数据内容 content, 并提供了 isValid 状态和 processingLog 的变更方法, 在责任链中进行传递数据。
模板方法模式(抽象类)
public abstract class AbstractDataHandler {

    public final void handle(RawData data) {

        if (!data.isValid()) {
            System.out.println("数据无效, 跳过当前处理步骤。");
            return;
        }

        System.out.println("开始处理: " + this.getClass().getSimpleName());
        preProcess(data);
        doProcess(data);
        postProcess(data);
        System.out.println("完成处理: " + this.getClass().getSimpleName());

    }

    protected void preProcess(RawData data) {

    }

    protected abstract void doProcess(RawData data);

    protected void postProcess(RawData data) {

    }

}
  • 定义了数据处理的通用骨架方法 handle(RawData data), 固定了处理的顺序 preProcess(data) -> doProcess(data) -> postProcess(data) ,其中 doProcess() 是抽象方法, 强制子类实现核心处理逻辑,
  • preProcesspostProcess 是钩子方法, 提供默认实现, 子类可以选择性的进行重写。
责任链模式(抽象处理者)****
public abstract class DataProcessor {

    protected DataProcessor nextProcessor;

    protected AbstractDataHandler internalHandler;

    public DataProcessor(AbstractDataHandler internalHandler) {
        this.internalHandler = internalHandler;
    }

    public void setNextProcessor(DataProcessor nextProcessor) {
        this.nextProcessor = nextProcessor;
    }

    public void process(RawData data) {
        if (!data.isValid()) {
            System.out.println("数据在上一个环节已标记为无效, 跳过当前处理器: " + this.getClass().getSimpleName());
            return;
        }

        internalHandler.handle(data);

        if (data.isValid() && nextProcessor != null) {
            nextProcessor.process(data);
        }
        else if (!data.isValid()) {
            System.out.println("数据在 " + this.getClass().getSimpleName() + "处理后变为无效, 责任链中断。");
        }
    }
}
  • 承担责任链模式中的抽象处理者角色, 持有一个 nextProcessor 引用来构建链, 并持有一个 AbstractDataHandler 实例作为内部处理逻辑的实现。
  • process(RawData data) 方法是责任链的核心, 首先检查数据有效性, 然后调用内部的 internalHandler.handle(data) 来执行具体的处理逻辑, 最后根据数据状态决定是否将请求传递给下一个处理器。
责任链模式-具体处理者
public class DataCleaningProcessor extends DataProcessor {

    public DataCleaningProcessor() {
        super(new AbstractDataHandler() {

            @Override
            protected void preProcess(RawData data) {
                System.out.println(" 清理预处理: 移除多余空格。");
                data.setContent(data.getContent().trim());
            }

            @Override
            protected void doProcess(RawData data) {
                System.out.println(" 清洗核心处理: 替换敏感词。");
                String cleanedContent = data.getContent().replace("敏感词""***");
                data.setContent(cleanedContent);
                data.addProcessingLog("数据清洗");
            }

            @Override
            protected void postProcess(RawData data) {
                System.out.println(" 清洗后处理: 转换为小写。");
                data.setContent(data.getContent().toLowerCase());
            }
        });
    }
}

public class DataValidationProcessor extends DataProcessor {

    public DataValidationProcessor() {
        super(new AbstractDataHandler() {
            @Override
            protected void doProcess(RawData data) {
                System.out.println(" 校验核心处理: 检查数据长度和内容。");
                if (data.getContent().length() < 5 || data.getContent().contains("error")) {
                    data.setValid(false);
                    data.addProcessingLog("数据校验失败");
                    System.out.println(" 数据校验失败: 内容过短或包含'error'。");
                }
                else {
                    data.addProcessingLog("数据校验通过");
                    System.out.println(" 数据校验通过。");
                }
            }
        });
    }
}

public class DataEncryptionProcessor extends DataProcessor {

    public DataEncryptionProcessor() {
        super(new AbstractDataHandler() {
            @Override
            protected void doProcess(RawData data) {
                System.out.println(" 加密核心处理: 简单Base64编码。");
                String encodedContent = Base64.getEncoder().encodeToString(data.getContent().getBytes());
                data.setContent(encodedContent);
                data.addProcessingLog("数据加密");
            }

            @Override
            protected void postProcess(RawData data) {
                System.out.println(" 加密后处理: 记录加密类型。");
            }
        });
    }
}
  • 作为责任链模式中的具体处理者角色, 继承了 DataProcessor, 在构造函数中通过匿名内部类的方式, 为 AbstractDataHandler 提供了具体实现。
测试类
public class ChainTemplateTest {

    @Test
    public void test_chain_template() {
        DataCleaningProcessor cleaningProcessor = new DataCleaningProcessor();
        DataValidationProcessor validationProcessor = new DataValidationProcessor();
        DataEncryptionProcessor encryptionProcessor = new DataEncryptionProcessor();

        cleaningProcessor.setNextProcessor(validationProcessor);
        validationProcessor.setNextProcessor(encryptionProcessor);

        System.out.println("\n--- 正常数据处理(预期: 清洗->校验通过->加密) ---");
        RawData data1 = new RawData(" Hello World, 这是一个敏感词测试 ");
        cleaningProcessor.process(data1);
        System.out.println("处理后数据: " + data1);

        System.out.println("\n--- 包含错误的数据(预期: 清洗->校验失败,责任链中断) ---");
        RawData data2 = new RawData(" short error data ");
        System.out.println("原始数据: " + data2);
        cleaningProcessor.process(data2);
        System.out.println("处理后数据: " + data2);

        System.out.println("\n--- 仅需清洗和加密的数据(假设校验器被移除) ---");
        cleaningProcessor.setNextProcessor(encryptionProcessor);
        RawData data3 = new RawData(" another sensitive word example ");
        System.out.println("原始数据: " + data3);
        cleaningProcessor.process(data3);
        System.out.println("处理后数据: " + data3);

    }

}
执行结果
--- 正常数据处理(预期: 清洗->校验通过->加密) ---
开始处理: 
 清理预处理: 移除多余空格。
 清洗核心处理: 替换敏感词。
 清洗后处理: 转换为小写。
完成处理: 
开始处理: 
 校验核心处理: 检查数据长度和内容。
 数据校验通过。
完成处理: 
开始处理: 
 加密核心处理: 简单Base64编码。
 加密后处理: 记录加密类型。
完成处理: 
处理后数据: 原始数据 [内容: "aGVsbG8gd29ybGQsIOi/meaYr+S4gOS4qioqKua1i+ivlQ==", 有效: true, 日志: 数据清洗 | 数据校验通过 | 数据加密]

--- 包含错误的数据(预期: 清洗->校验失败,责任链中断) ---
原始数据: 原始数据 [内容: " short error data ", 有效: true, 日志: ]
开始处理: 
 清理预处理: 移除多余空格。
 清洗核心处理: 替换敏感词。
 清洗后处理: 转换为小写。
完成处理: 
开始处理: 
 校验核心处理: 检查数据长度和内容。
 数据校验失败: 内容过短或包含'error'。
完成处理: 
数据在 DataValidationProcessor处理后变为无效, 责任链中断。
处理后数据: 原始数据 [内容: "short error data", 有效: false, 日志: 数据清洗 | 数据校验失败]

--- 仅需清洗和加密的数据(假设校验器被移除) ---
原始数据: 原始数据 [内容: " another sensitive word example ", 有效: true, 日志: ]
开始处理: 
 清理预处理: 移除多余空格。
 清洗核心处理: 替换敏感词。
 清洗后处理: 转换为小写。
完成处理: 
开始处理: 
 加密核心处理: 简单Base64编码。
 加密后处理: 记录加密类型。
完成处理: 
处理后数据: 原始数据 [内容: "YW5vdGhlciBzZW5zaXRpdmUgd29yZCBleGFtcGxl", 有效: true, 日志: 数据清洗 | 数据加密]

Process finished with exit code 0

组合优势

  • 责任链模式提供了数据处理流程的宏观控制(执行顺序、中断), 模板方法模式则在每个处理环节内部提供了微观的步骤定制能力。使得整个数据处理管道既有清晰的流程, 又能灵活的定制每个步骤的细节。