杂记 - 状态模式 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。
  • 这样实现了请求处理的灵活扩展和解耦。
相关推荐
sunlifenger4 小时前
嵌入式部署,解锁张家港智慧灯杆的“极简组网”密码
科技·状态模式
上火的金鱼妹1 天前
关于多进程sse连接通知的实战
javascript·状态模式·sse
阿俊-全栈开发1 天前
LikeShop 小程序商城首页可配置弹窗的设计与实现(Java + uni-app)
小程序·状态模式·likeshop·likeshop开源商城
lingyubb2 天前
配音工具怎么选?从 TTS 合成链路看 6 个可量化参数
状态模式
平头哥技术团队3 天前
从预订问到退房:一间山野民宿的数字人「旅程地图」——Theme07_Homestay.vue 端到端拆解
状态模式·数字人
未来之窗软件服务4 天前
web网络请求竞态问题与取消方案-东方仙盟
前端·状态模式·仙盟创梦ide·东方仙盟·网络取消
一级新生5 天前
多智能体协作:常用协作模式详解
人工智能·状态模式·agent·多智能体·智能体
喜欢打篮球的普通人7 天前
LLVM 前端与优化层:Clang 如何把 C 代码变成 IR
c语言·前端·状态模式
m0_敲代码的彭于晏1688 天前
Vercel 前端部署与全栈开发实战指南
前端·状态模式
星恒随风8 天前
Linux线程同步与互斥(二):从日志系统与线程池设计,到线程安全单例、可重入函数和死锁原理
linux·运维·状态模式