杂记 - 状态模式 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。
  • 这样实现了请求处理的灵活扩展和解耦。
相关推荐
apolloyhl12 小时前
State 状态模式
状态模式
冬奇Lab15 小时前
【Kotlin系列14】编译器插件与注解处理器开发:在编译期操控Kotlin
android·开发语言·kotlin·状态模式
前端不太难18 小时前
为什么 HarmonyOS PC 应用离不开文档模型
华为·状态模式·harmonyos
a程序小傲1 天前
高并发下如何防止重复下单?
java·开发语言·算法·面试·职场和发展·状态模式
小码过河.2 天前
设计模式——状态模式
ui·状态模式
前端不太难2 天前
HarmonyOS 后台机制,对实时游戏意味着什么?
游戏·状态模式·harmonyos
前端不太难5 天前
Flutter / RN / iOS 的状态策略,该如何取舍?
flutter·ios·状态模式
小夏卷编程6 天前
jeecg boot 3.2.0 用户token刷新在线用户显示问题
状态模式
Yvonne爱编码8 天前
前端工程化进阶:从搭建完整项目脚手架到性能优化【技术类】
前端·状态模式
虫小宝9 天前
基于责任链模式构建可扩展的微信群发消息风控过滤器(Java实现)
android·java·责任链模式