杂记 - 状态模式 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。
  • 这样实现了请求处理的灵活扩展和解耦。
相关推荐
前端不太难19 小时前
经典游戏 Claw 的引擎是怎么被逆向出来的
游戏·状态模式
青槿吖1 天前
SpringMVC通关秘籍(下):日期转换器、拦截器与文件上传的奇幻冒险
java·开发语言·数据库·sql·mybatis·状态模式
尤山海1 天前
深度防御:内容类网站如何有效抵御 SQL 注入与脚本攻击(XSS)
前端·sql·安全·web安全·性能优化·状态模式·xss
i建模2 天前
利用AI生成程序界面
状态模式
别催小唐敲代码2 天前
前后端交互原理与架构全解
架构·状态模式·前后端
小箌3 天前
springboot_03
spring boot·后端·状态模式
Detachym3 天前
InsightFlow 服务配置优化与部署实践
java·spring boot·tomcat·maven·状态模式·jar
GISer_Jing3 天前
AI Agent技能Skills设计
前端·人工智能·aigc·状态模式
前端不太难3 天前
开源社区如何复活一款经典游戏
游戏·开源·状态模式
欧阳天羲4 天前
AI 时代前端工程师发展路线
前端·人工智能·状态模式