设计模式——责任链模式实战,优雅处理Kafka消息

一、业务背景

Kafka接收消息,需要A,B,C...多种策略做处理,再通过http请求发送给下游。多种策略混在一起很难维护,通过责任链模式把每种策略的代码收敛到自己的Handler中

二、具体设计

classDiagram Handler <|-- StrategyAHandler Handler <|-- StrategyBHandler Handler <|-- UploadHandler Handler: +void handleUserData(UserContext, HandlerChain) Handler: +void handleOrderData(OrderContext, HandlerChain) class StrategyAHandler { +void handleUserData(UserContext, HandlerChain) +void handleOrderData(OrderContext, HandlerChain) } class StrategyBHandler { +void handleUserData(UserContext, HandlerChain) +void handleOrderData(OrderContext, HandlerChain) } class UploadHandler { +void handleUserData(UserContext, HandlerChain) +void handleOrderData(OrderContext, HandlerChain) } HandlerChain o--o Handler class HandlerChain { +List~Handler~ chain +void doHandle(AbstractContext context) } HandlerChain --> AbstractContext class AbstractContext { +JSONObject param +int position } AbstractContext <|-- UserContext AbstractContext <|-- OrderContext class UserContext { +UserInfo userInfo } class OrderContext { +OrderInfo orderInfo }

三、代码实现

1.HandlerChain类

java 复制代码
public class HandlerChain {

    List<Handler> chain;
    
    public HandlerChain() {
        chain = new ArrayList<>();
    }
    
    public void doHandle(AbstractContext context) {
        // 截止条件
        if (context.getPosition() >= chain.size()) {
            return;
        }
        // 获取当前要执行的handler
        Handler handler = chain.get(context.getPosition());
        // 移动到下一个要执行的handler位置
        context.setPosition(context.getPosition() + 1);
        // 利用Context类的多态,判断执行的具体方法
        if (context instanceof UserContext) {
            handler.handleUserData((UserContext) context, this);
        } else if (context instanceof OrderContext) {
            handler.handleOrderData((OrderContext) context, this);
        }
    }
    
    public void addHandler(Handler handler) {
        chain.add(hander);
    }

}

2.Handler类

  • Handler接口:定义需要处理的消息
java 复制代码
public interface Handler {
    // 处理用户数据消息
    void handleUserData(UserContext userContext, HandlerChain chain);
    // 处理订单数据消息
    void handleOrderData(OrderContext orderContext, HandlerChain chain);
}
  • Handler实现类:子类结构相同,执行各自的具体逻辑
java 复制代码
@Component
public class StrategyAHandler implements Handler {
    // 处理用户数据消息
    public void handleUserData(UserContext userContext, HandlerChain chain) {
        // ...
        // 核心方法,触发流转到下一个handler
        chain.doHandle(userContext);
    }
    // 处理订单数据消息
    public void handleOrderData(OrderContext orderContext, HandlerChain chain) {
        ...
        // 核心方法,触发流转到下一个handler
        chain.doHandle(orderContext);
    }
}

@Component
public class StrategyBHandler implements Handler {
 // ...
}

@Component
public class UploadHandler implements Handler {
 // ...
}

3.Context类

  • Context抽象类 :定义公共参数
    • param:处理到最后要发http请求,因此构建一个公共的JSONObject类型参数
    • position:标记即将执行的handler所在位置
java 复制代码
@Data
public abstract class AbstractContext {
    private JSONObject param = new JSONObject();
    private int position = 0;
}
  • Context实现类:定义每一种消息独有的参数
java 复制代码
@Data
public class UserContext extends AbstractContext {
    private UserInfo userInfo;
    
    public UserContext(UserInfo userInfo) {
        this.userInfo = userInfo;
    }
}
java 复制代码
@Data
public class OrderContext extends AbstractContext {
    private OrderInfo orderInfo;
    
    public OrderContext(OrderInfo orderInfo) {
        this.orderInfo = orderInfo;
    }
}

4.Handler组装类

  • 作用:接收Kafka消息,把各种策略按任意顺序组装
java 复制代码
@Component
public class DemoService {
    @Autowired
    private StrategyAHandler strategyAHandler;
    @Autowired
    private StrategyBHandler strategyBHandler;
    @Autowired
    private UploadHandler uploadHandler;
    
    // 处理Kafka发来的用户信息
    public void handleUserData(UserInfo userInfo) {
        HandlerChain chain = new HandlerChain();
        chain.addHandler(strategyAHandler);
        chain.addHandler(strategyBHandler);
        chain.addHandler(uploadHandler);
        UserContext userContext = new UserContext(userInfo);
        chain.doHandle(userContext);
    }
    
    // 处理Kafka发来的订单信息
    public void handleOrderData(OrderInfo orderInfo) {
        HandlerChain chain = new HandlerChain();
        chain.addHandler(strategyBHandler);
        chain.addHandler(strategyAHandler);
        chain.addHandler(uploadHandler);
        OrderContext orderContext = new OrderContext(orderInfo);
        chain.doHandle(orderContext);
    }
}

四、总结

  • Handler实现类交给Spring框架来管理,Context和HandlerChain则是每次调用创建一份
  • 实现效果是可以把某个策略的代码收敛在一个Handler实现类中
  • 如果需要去掉某个策略,直接把该策略从chain中去除即可
相关推荐
Oneslide19 分钟前
Ubuntu 26.04 完整安装 Fcitx5 中文拼音输入法指南(适配默认Wayland)
后端
huangdong_1 小时前
电商平台图片URL原图转换技术深度解析:从缩略图到高清原图的完整方案
java·后端·spring
掘金码甲哥1 小时前
3min手搓一个帮助文档站,很合理吧!
后端
一只旭宝1 小时前
【C++入门精讲22】常见设计模式
c++·设计模式
ServBay5 小时前
别再用初级写法写Rust了,8个写法你值得拥有
后端·rust
jingling5556 小时前
go | 环境安装和快速入门
开发语言·后端·golang
Darren2456 小时前
流程步骤模板 - @StepStatus 注解方案
后端
小闹5496 小时前
Claude Code 给自己接了一部飞书,从此不用守在工位等它
后端·claude
浮游本尊6 小时前
Java学习第41天 - 复杂查询、多表关联、索引优化与慢 SQL 调优
后端