设计模式——责任链模式实战,优雅处理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中去除即可
相关推荐
爱勇宝5 小时前
第 1 章:别把“需求文档”当成真正的需求
前端·后端·程序员
端庄的战斗机8 小时前
javascript 设计模式(文章很长,请自备瓜子,水果和眼药水)
开发语言·javascript·设计模式
IT_陈寒10 小时前
闭包陷阱让我加了两天班,JavaScript你真行
前端·人工智能·后端
易协同低代码11 小时前
通达OA核心类库TD类深度解析
后端
Gopher_HBo11 小时前
Go语言学习笔记(十八)Gin处理Session
后端
谭光志12 小时前
工具塞满上下文窗口怎么办?深度拆解 AI Agent Tool Search 按需加载实现原理
前端·后端·ai编程
她说..12 小时前
Java 默认值设置方式
java·开发语言·后端·springboot
foggyprojects12 小时前
从0开始,一句话启动AI DataAgent
后端·数据分析·ai编程
郡杰12 小时前
一些基础和问题解决
后端
陈随易12 小时前
前端项目部署只要30秒
前端·后端·程序员