杂记 - 状态模式 VS. 责任链模式

目录

一、总体对比

状态模式和责任链模式都是行为型设计模式,但它们的意图和应用场景不同:

对比项 状态模式 责任链模式
意图 允许对象在内部状态改变时改变它的行为, 看起来就像改变了其类。 使多个对象都有机会处理请求,将这些对象连成一条链, 并沿着这条链传递请求,直到有对象处理它为止。
结构 通常有一个上下文(Context)对象和多个状态(State)对象。 上下文持有当前状态的引用,行为委托给当前状态对象。 有一个处理者接口,每个处理者持有下一个处理者的引用。 请求沿链传递,直到被处理。
应用场景 对象的行为依赖于它的状态, 并且在运行时可能根据状态变化而改变行为。 有多个对象可以处理同一个请求, 具体由谁处理在运行时决定。
示例 工作流引擎、订单状态流转、TCP连接状态。 Java Web Filter、日志处理链、审批流。
总结 状态模式关注"对象状态的切换", 每个状态封装一组行为,状态切换时行为也随之切换。 状态模式强调"同一个对象在不同状态下的行为变化"。 责任链模式关注"请求的传递", 每个处理者决定是否处理请求或传递给下一个处理者。 责任链模式强调"多个对象对同一请求的处理机会"。

二、状态模式

类图:
Client
Context

  • state: State
  • request()
    <<interface>>
    State
  • handle(Context)
    ConcreteStateA
  • handle(Context)
    ConcreteStateB
  • handle(Context)

示例代码:

java 复制代码
public interface State {
    void handle(Context context);
}

public class ConcreteStateA implements State {
    @Override
    public void handle(Context context) {
        System.out.println("当前状态:A,切换到B");
        context.setState(new ConcreteStateB());
    }
}

public class ConcreteStateB implements State {
    @Override
    public void handle(Context context) {
        System.out.println("当前状态:B,切换到A");
        context.setState(new ConcreteStateA());
    }
}

public class Context {
    private State state;

    public Context(State state) {
        this.state = state;
    }

    public void setState(State state) {
        this.state = state;
    }

    public void request() {
        if (state != null) {
            state.handle(this);
        }
    }
}

public class Client {
    public static void main(String[] args) {
        Context context = new Context(new ConcreteStateA());
        context.request(); // A -> B
        context.request(); // B -> A
    }
}

三、责任链模式

类图:
next
Client
<<abstract>>
Handler
+setNext(Handler)
+handleRequest(Request)
ConcreteHandlerA
+handleRequest(Request)
ConcreteHandlerB
+handleRequest(Request)

示例代码:

java 复制代码
public abstract class Handler {
    protected Handler next;

    public void setNext(Handler next) {
        this.next = next;
    }

    public abstract void handleRequest(String request);
}

public class ConcreteHandlerA extends Handler {
    @Override
    public void handleRequest(String request) {
        if ("A".equals(request)) {
            System.out.println("ConcreteHandlerA 处理请求: " + request);
        } else if (next != null) {
            next.handleRequest(request);
        } else {
            System.out.println("请求未被处理: " + request);
        }
    }
}

public class ConcreteHandlerB extends Handler {
    @Override
    public void handleRequest(String request) {
        if ("B".equals(request)) {
            System.out.println("ConcreteHandlerB 处理请求: " + request);
        } else if (next != null) {
            next.handleRequest(request);
        } else {
            System.out.println("请求未被处理: " + request);
        }
    }
}

public class Client {
    public static void main(String[] args) {
        Handler handlerA = new ConcreteHandlerA();
        Handler handlerB = new ConcreteHandlerB();
        handlerA.setNext(handlerB);

        handlerA.handleRequest("A"); // ConcreteHandlerA 处理请求: A
        handlerA.handleRequest("B"); // ConcreteHandlerB 处理请求: B
        handlerA.handleRequest("C"); // 请求未被处理: C
    }
}

两者本质区别:

状态模式是"状态驱动行为",责任链模式是"链式传递请求"。

四、扩展:手撸Java WebFilter实现

Java WebFilter 链式调用的实现原理是基于"责任链模式"(Chain of Responsibility Pattern)。每个 Filter 处理请求后,可以选择继续传递给下一个 Filter 或终止链路。Filter 链由容器(如 Tomcat)维护,依次调用每个 Filter 的 doFilter 方法,最后到达目标 Servlet。

原理简述:

  • 每个 Filter 通过 doFilter(ServletRequest, ServletResponse, FilterChain) 方法接收请求。
  • FilterChain 负责调用下一个 Filter 或最终的 Servlet。
  • 责任链模式:每个处理者(Filter)持有对下一个处理者(FilterChain)的引用。

示例代码:

自定义 Filter 实现:

java 复制代码
// MyFilter.java
import javax.servlet.*;
import java.io.IOException;

public class MyFilter implements Filter {
    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
            throws IOException, ServletException {
        // 前置处理
        System.out.println("MyFilter 前置处理");
        // 传递给下一个 Filter 或 Servlet
        chain.doFilter(request, response);
        // 后置处理
        System.out.println("MyFilter 后置处理");
    }
}

责任链模式简化实现(模拟 FilterChain):

java 复制代码
// Filter.java
public interface Filter {
    void doFilter(Request request, Response response, FilterChain chain);
}

// FilterChain.java
import java.util.List;

public class FilterChain {
    private List<Filter> filters;
    private int index = 0;

    public FilterChain(List<Filter> filters) {
        this.filters = filters;
    }

    public void doFilter(Request request, Response response) {
        if (index < filters.size()) {
            filters.get(index++).doFilter(request, response, this);
        } else {
            // 最终处理(如Servlet)
            System.out.println("到达最终处理(Servlet)");
        }
    }
}

// Request.java / Response.java
public class Request {}
public class Response {}

使用链式调用:

java 复制代码
// Main.java
import java.util.Arrays;

public class Main {
    public static void main(String[] args) {
        Filter filter1 = (req, res, chain) -> {
            System.out.println("Filter1 前置");
            chain.doFilter(req, res);
            System.out.println("Filter1 后置");
        };
        Filter filter2 = (req, res, chain) -> {
            System.out.println("Filter2 前置");
            chain.doFilter(req, res);
            System.out.println("Filter2 后置");
        };
        FilterChain chain = new FilterChain(Arrays.asList(filter1, filter2));
        chain.doFilter(new Request(), new Response());
    }
}

输出示例:

复制代码
Filter1 前置
Filter2 前置
到达最终处理(Servlet)
Filter2 后置
Filter1 后置

总结:

  • Filter 链式调用本质是责任链模式的应用。
  • 每个 Filter 处理完后通过 chain.doFilter 传递给下一个 Filter 或最终 Servlet。
  • 这样实现了请求处理的灵活扩展和解耦。
相关推荐
cpp_learners16 小时前
C++ 实现责任链模式(Chain of Responsibility):从一堆 if-else 到可插拔的处理管道
开发语言·c++·责任链模式
weixin_493503672 天前
Vue3 前端生成 PDF:会员证书与活动签到表的三种打印方案与踩坑记录
前端·pdf·状态模式
晴天163 天前
前端跨域方案解析:JSONP 的原理、实战与演进
前端·状态模式
晴天163 天前
HTML iframe 标签全面解析:原理、属性、实战场景与最佳实践
前端·html·状态模式
nvd113 天前
深入现代 Web 鉴权架构:网关统一代理 (Forward-Auth) vs 前端持有 JWT 的终极选型与边缘同域实践
前端·架构·状态模式
你别说话了4 天前
Vue3对接AI Agent: 封装流式对话组件
状态模式
陈驰_05044 天前
需求列表接口 422 Unprocessable Entity 排查与修复全记录
状态模式·fastapi·vue 3
两点王爷5 天前
Java 与前端加载 MVT 数据:从服务端切片到浏览器渲染
java·前端·状态模式
码匠许师傅5 天前
【设计模式精讲】25.状态模式(State)
c++·ui·设计模式·状态模式·uml
szarron5 天前
国产手持式频谱分析仪选型攻略:TFN RC系列 vs HTOOL SA8T频谱分析仪 专业参数对比(军工/路测/调试全覆盖)
开发语言·前端·状态模式