设计模式 六月 03, 2021

责任链模式

文章字数 9.7k 阅读约需 9 mins. 阅读次数 0

责任链模式

解决问题

避免请求发送者与接收者耦合在一起,让多个对象都有可能接收请求,将这些对象连接成一条链,并且沿着这条链传递请求,直到有对象处理它为止。

方案

职责链上的处理者负责处理请求,客户只需要将请求发送到职责链上即可,无须关心请求的处理细节和请求的传递,所以职责链将请求的发送者和请求的处理者解耦了。

结构

责任链模式

  • 抽象处理者(Handler):定义一个请求处理的方法,并维护一个下一个处理节点 Handler 对象的引用;

  • 具体处理者(ConcreteHandler):对请求进行处理,如果不感兴趣,则进行转发.

    // 通用代码
    class Client {
        public static void main(String[] args) {
            Handler handlerA = new ConcreteHandlerA();
            Handler handlerB = new ConcreteHandlerB();
            handlerA.setnextHanlder(handlerB);
            handlerA.handleRequest("requestB");
        }
    
        static abstract class Handler {
            protected Handler mNextHandler;
    
            public void setnextHanlder(Handler successor) {
                this.mNextHandler = successor;
            }
    
            public abstract void handleRequest(String request);
        }
    
        static class ConcreteHandlerA extends Handler {
    
            @Override
            public void handleRequest(String request) {
                if ("requestA".equals(request)) {
                    System.out.println(String.format("%s deal with request: %s", this.getClass().getSimpleName(), request));
                    return;
                }
                if (this.mNextHandler != null) {
                    this.mNextHandler.handleRequest(request);
                }
            }
        }
        static class ConcreteHandlerB extends Handler {
    
            @Override
            public void handleRequest(String request) {
                if ("requestB".equals(request)) {
                    System.out.println(String.format("%s deal with request: %s", this.getClass().getSimpleName(), request));
                    return;
                }
                if (this.mNextHandler != null) {
                    this.mNextHandler.handleRequest(request);
                }
            }
        }
    }
    

适用性

  1. 有多个对象可以处理同一个请求,具体哪个对象处理该请求由运行时刻自动确定。
  2. 在不明确指定接收者的情况下,向多个对象中的一个提交一个请求。
  3. 可动态指定一组对象处理请求

优缺点

优点

  • 降低耦合度。它将请求的发送者和接收者解耦。
  • 简化了对象。使得对象不需要知道链的结构。
  • 增强给对象指派职责的灵活性。通过改变链内的成员或者调动它们的次序,允许动态地新增或者删除责任。
  • 增加新的请求处理类很方便。

缺点

  • 系统性能将受到一定影响,而且在进行代码调试时不太方便,可能会造成循环调用。
  • 可能不容易观察运行时的特征,有碍于除错。

经典实现

请假流程

// 请求事件类
public class LeaveRequest {
    /**天数*/
    private int leaveDays;

    /**姓名*/
    private String name;
}

// 抽象处理者
public class AbstractLeaveHandler {
    /**直接主管审批处理的请假天数*/
    protected int MIN = 1;
    /**部门经理处理的请假天数*/
    protected int MIDDLE = 3;
    /**总经理处理的请假天数*/
    protected int MAX = 30;

    /**领导名称*/
    protected String handlerName;

    /**下一个处理节点(即更高级别的领导)*/
    protected AbstractLeaveHandler nextHandler;

    /**设置下一节点*/
    protected void setNextHandler(AbstractLeaveHandler handler){
        this.nextHandler = handler;
    }

    /**处理请假的请求,子类实现*/
    protected void handlerRequest(LeaveRequest request){

    }
}

// 直接上级审批.
public class DirectLeaderLeaveHandler extends AbstractLeaveHandler{
    public DirectLeaderLeaveHandler(String name) {
        this.handlerName = name;
    }

    @Override
    protected void handlerRequest(LeaveRequest request) {
        if(request.getLeaveDays() <= this.MIN){
            System.out.println("直接主管:" + handlerName + ",已经处理;流程结束。");
            return;
        }

        if(null != this.nextHandler){
            this.nextHandler.handlerRequest(request);
        }else{
            System.out.println("审批拒绝!");
        }

    }
}

// 部门经理审批
public class DeptManagerLeaveHandler extends AbstractLeaveHandler {

    public DeptManagerLeaveHandler(String name) {
        this.handlerName = name;
    }

    @Override
    protected void handlerRequest(LeaveRequest request) {
        if(request.getLeaveDays() >this.MIN && request.getLeaveDays() <= this.MIDDLE){
            System.out.println("部门经理:" + handlerName + ",已经处理;流程结束。");
            return;
        }

        if(null != this.nextHandler){
            this.nextHandler.handlerRequest(request);
        }else{
            System.out.println("审批拒绝!");
        }
    }
}

// 总经理审批
public class GManagerLeaveHandler extends AbstractLeaveHandler {
    public GManagerLeaveHandler(String name) {
        this.handlerName = name;
    }

    @Override
    protected void handlerRequest(LeaveRequest request) {
        if(request.getLeaveDays() > this.MIDDLE && request.getLeaveDays() <= this.MAX){
            System.out.println("总经理:" + handlerName + ",已经处理;流程结束。");
            return;
        }

        if(null != this.nextHandler){
            this.nextHandler.handlerRequest(request);
        }else{
            System.out.println("审批拒绝!");
        }
    }
}


public class Demo {
    public static void main(String[] args) {
        LeaveRequest request = LeaveRequest.builder().leaveDays(20).name("张三").build();


        AbstractLeaveHandler directLeaderLeaveHandler = new DirectLeaderLeaveHandler("主管张某");
        DeptManagerLeaveHandler deptManagerLeaveHandler = new DeptManagerLeaveHandler("经理李某");
        GManagerLeaveHandler gManagerLeaveHandler = new GManagerLeaveHandler("总经理王某");

        
        if(request.leaveDays > 3){
            directLeaderLeaveHandler.setNextHandler(deptManagerLeaveHandler);
        }
         if(request.leaveDays > 5){
            deptManagerLeaveHandler.setNextHandler(gManagerLeaveHandler);     
         }  
        // 链式处理.
        directLeaderLeaveHandler.handlerRequest(request);
    }
}

模拟服务器请求的拦截器,包含嵌套责任链.

import java.util.ArrayList;
import java.util.List;

public class Demo {
    public static void main(String[] args) {
        Msg msg = new Msg();
        msg.setMsg("大家好:),<script>,欢迎访问 本网站. ");
        // 创建一条责任链
        FilterChain fc = new FilterChain();
        
        // 制定规则
        fc.add(new HTMLFilter())
                .add(new SensitiveFilter());

        // 创建一条责任链
        FilterChain fc2 = new FilterChain();
        // 制定规则
        fc2.add(new FaceFilter()).add(new URLFilter());

        // 将第二条责任链接到第一条责任链上.
        fc.add(fc2);
        // 启动执行责任链
        fc.doFilter(msg);
        System.out.println(msg);

    }
}

class Msg {
    String name;
    String msg;

    public String getMsg() {
        return msg;
    }

    public void setMsg(String msg) {
        this.msg = msg;
    }

    @Override
    public String toString() {
        return "Msg{" +
                "msg='" + msg + '\'' +
                '}';
    }
}

interface Filter {
    boolean doFilter(Msg m);
}

class HTMLFilter implements Filter {
    @Override
    public boolean doFilter(Msg m) {
        String r = m.getMsg();
        r = r.replace('<', '[');
        r = r.replace('>', ']');
        m.setMsg(r);
        return true;
    }
}

class SensitiveFilter implements Filter {
    @Override
    public boolean doFilter(Msg m) {
        String r = m.getMsg();
        r = r.replaceAll("大家好", "各位老爷好.");
        m.setMsg(r);
        return false;
    }
}

class FaceFilter implements Filter {
    @Override
    public boolean doFilter(Msg m) {
        String r = m.getMsg();
        r = r.replace(":)", "^V^");
        m.setMsg(r);
        return true;
    }
}

class URLFilter implements Filter {
    @Override
    public boolean doFilter(Msg m) {
        String r = m.getMsg();
        r = r.replace("本网站", "http://konghenying.github.com");
        m.setMsg(r);
        return true;
    }
}

class FilterChain implements Filter {
    private List<Filter> filters = new ArrayList<>();

    public FilterChain add(Filter f) {
        filters.add(f);
        return this;
    }

    // 带参数返回的执行方法.
    public boolean doFilter(Msg m) {
        for(Filter f : filters) {
            // 判断是否还要继续执行,false就退出当前责任链.
            if(!f.doFilter(m)) return false;
        }

        return true;
    }
}

框架中实现

servlet 的 Filter,网关的拦截,js的事件冒泡机制.

0%