设计模式——责任链模式实战,优雅处理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中去除即可
相关推荐
困死了11118 小时前
设计模式-注册表模式
设计模式
没逻辑9 小时前
gocron - 分布式定时任务管理系统
后端
程序猿DD9 小时前
人工智能如何改变 Anthropic 的工作方式
java·后端
桦说编程9 小时前
Guava Forwarding系列类详解——装饰器模式实战
java·后端·设计模式
VX:Fegn089510 小时前
计算机毕业设计|基于springboot + vue敬老院管理系统(源码+数据库+文档)
数据库·vue.js·spring boot·后端·课程设计
算法与双吉汉堡10 小时前
【短链接项目笔记】Day2 用户注册
java·redis·笔记·后端·spring
Victor35611 小时前
Netty(18)Netty的内存模型
后端
Victor35611 小时前
Netty(17)Netty如何处理大量的并发连接?
后端