侧边栏壁纸
博主头像
峰峰火火博主等级

一条咸鱼罢了

  • 累计撰写 124 篇文章
  • 累计创建 90 个标签
  • 累计收到 59 条评论

目 录CONTENT

文章目录

设计模式-责任链

峰峰火火
2023-09-14 / 0 评论 / 0 点赞 / 323 阅读 / 668 字 / 正在检测是否收录...
温馨提示:
若内容或图片失效,请留言反馈。部分素材来自网络,若不小心影响到您的利益,请联系我们删除。

描述

使多个对象都有机会处理请求,从而避免请求的发送者和接收者之间的耦合关系。将这些对象连成一条链,并沿着这条链发送该请求,直到有一个对象处理它为止。

使用

最近在做ChatGPT项目时,用到了这么个设计模式,用户发送消息,先进行敏感词过滤,再判断是否IP限制,再判断是否有额度,最后进行消息回答。

类图

image-1694673799251

接口

package org.xiaobai.ai.handler.emitter;

import org.springframework.web.servlet.mvc.method.annotation.ResponseBodyEmitter;
import org.xiaobai.ai.api.domain.request.ChatProcessRequest;

/**
 * ResponseBodyEmitter 链路
 * 责任链模式实现
 */
public interface ResponseEmitterChain {

    /**
     * 处理请求
     *
     * @param request 请求对象
     * @param emitter 响应对象
     */
    void doChain(ChatProcessRequest request, ResponseBodyEmitter emitter);

    /**
     * 获取下一个处理器
     *
     * @return 下一个处理器
     */
    ResponseEmitterChain getNext();

    /**
     * 设置下一个处理器
     *
     * @param next 下一个处理器
     */
    void setNext(ResponseEmitterChain next);

    /**
     * 获取前一个处理器
     *
     * @return 前一个处理器
     */
    ResponseEmitterChain getPrev();

    /**
     * 设置前一个处理器
     *
     * @param prev 前一个处理器
     */
    void setPrev(ResponseEmitterChain prev);
}

抽象类

package org.xiaobai.ai.handler.emitter;

/**
 * 抽象的响应 Emitter 链路实现类,实现了 ResponseEmitterChain 接口
 */
public abstract class AbstractResponseEmitterChain implements ResponseEmitterChain {

    /**
     * 下一个链路节点
     */
    private ResponseEmitterChain next;

    /**
     * 上一个链路节点
     */
    private ResponseEmitterChain prev;

    @Override
    public ResponseEmitterChain getNext() {
        return next;
    }

    @Override
    public void setNext(ResponseEmitterChain next) {
        // 设置下一个节点,并将当前节点设置为下一个节点的上一个节点
        this.next = next;
        next.setPrev(this);
    }

    @Override
    public ResponseEmitterChain getPrev() {
        return prev;
    }

    @Override
    public void setPrev(ResponseEmitterChain prev) {
        this.prev = prev;
    }
}

实现类

只拿ip过滤例子

package org.xiaobai.ai.handler.emitter;

import cn.hutool.core.lang.Pair;
import cn.hutool.core.util.StrUtil;
import lombok.AllArgsConstructor;
import org.springframework.web.servlet.mvc.method.annotation.ResponseBodyEmitter;
import org.xiaobai.ai.api.domain.request.ChatProcessRequest;
import org.xiaobai.ai.api.domain.vo.ChatReplyMessageVO;
import org.xiaobai.ai.handler.RateLimiterHandler;
import org.xiaobai.core.utils.ObjectMapperUtil;
import org.xiaobai.core.utils.WebUtil;

import java.io.IOException;

/**
 * Ip 限流处理
 */
@AllArgsConstructor
public class IpRateLimiterEmitterChain extends AbstractResponseEmitterChain {

    @Override
    public void doChain(ChatProcessRequest request, ResponseBodyEmitter emitter) {
        try {
            String ip = WebUtil.getIp();
            // 根据ip判断是够可放行
            Pair<Boolean, String> limitPair = RateLimiterHandler.allowRequest(ip);
            if (limitPair.getKey()) {
                if (getNext() != null) {
                    getNext().doChain(request, emitter);
                }
            } else {
                ChatReplyMessageVO chatReplyMessageVO = ChatReplyMessageVO.onEmitterChainException(request);
                chatReplyMessageVO.setText(StrUtil.format("当前访问人数过多,请等到 {} 后再尝试下", limitPair.getValue()));
                emitter.send(ObjectMapperUtil.toJson(chatReplyMessageVO));
                emitter.complete();
            }
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }
}

使用

    @Override
    public ResponseBodyEmitter sendMessage(ChatProcessRequest chatProcessRequest) {
        // 超时时间设置 3 分钟
        ResponseBodyEmitter emitter = new ResponseBodyEmitter(3 * 60 * 1000L);
        emitter.onCompletion(() -> log.debug("请求参数:{},Front-end closed the emitter connection.", ObjectMapperUtil.toJson(chatProcessRequest)));
        emitter.onTimeout(() -> log.error("请求参数:{},Back-end closed the emitter connection.", ObjectMapperUtil.toJson(chatProcessRequest)));
        // 构建 emitter 处理链路
        ResponseEmitterChain ipRateLimiterEmitterChain = new IpRateLimiterEmitterChain();
        ResponseEmitterChain sensitiveWordEmitterChain = new SensitiveWordEmitterChain();
        ResponseEmitterChain chatLimiterEmitterChain = new ChatLimiterEmitterChain();
        sensitiveWordEmitterChain.setNext(new ChatMessageEmitterChain());
        ipRateLimiterEmitterChain.setNext(sensitiveWordEmitterChain);
        chatLimiterEmitterChain.setNext(ipRateLimiterEmitterChain);
        chatLimiterEmitterChain.doChain(chatProcessRequest, emitter);
        return emitter;
    }
0

评论区