设计模式之美学习-行为型-责任链模式(二十九)

什么是责任链模式

解释1:将请求的发送和接收解耦,让多个接收对象都有机会处理这个请求。将这些接收对象串成一条链,并沿着这条链传递这个请求,直到链上的某个接收对象能够处理它为止。

解释2:在职责链模式中,多个处理器(也就是刚刚定义中说的“接收对象”)依次处理同一个请求。一个请求先经过 A 处理器处理,然后再把请求传递给 B 处理器,B 处理器处理完后再传递给 C 处理器,以此类推,形成一个链条。链条上的每个处理器各自承担各自的处理职责,所以叫作职责链模式。

二种表现形式

表现形式1:通过链头开始执行,如果不能处理依次往下传递,直到能处理为止

表现形式2:通过链头开始执行 依次传递到联调尾

实现方式一

第一版

//抽象的Handler
public abstract class Handler {
    protected Handler successor = null;

    public void setSuccessor(Handler successor) {
        this.successor = successor;
    }

    public abstract void handle();
}
//链条上的处理器a
public class HandlerA extends Handler {
    @Override
    public boolean handle() {
        //标识自己是否能处理
        boolean handled = false;
        //... 省略处理逻辑 处理成功handled改为true
        //如果不能处理交给下一个handel处理
        if (!handled && successor != null) {
            //交给下一个handle处理
            successor.handle();
        }
    }
}
//联调上的处理器B
public class HandlerB extends Handler {
    @Override
    public void handle() {
        //标识自己是否能处理
        boolean handled = false;
        //... 省略处理逻辑 处理成功handled改为true
        //如果不能处理交给下一个handle处理
        if (!handled && successor != null) {
            successor.handle();
        }
    }
}

/**
 * HandlerChain 是处理器链,从数据结构的角度来看,它就是一个记录了链头、链尾的链表。
 * 其中,记录链尾是为了方便添加处理器
 */
public class HandlerChain {
    private Handler head = null;
    private Handler tail = null;

    public void addHandler(Handler handler) {
        handler.setSuccessor(null);
        if (head == null) {
            head = handler;
            tail = handler;
            return;
        }

        tail.setSuccessor(handler);
        tail = handler;
    }

    public void handle() {
        if (head != null) {
            //从链头依次往下传递
            head.handle();
        }
    }
}

// 使用举例
public class Application {
    public static void main(String[] args) {
        //管理链表
        HandlerChain chain = new HandlerChain();
        //添加处理器
        chain.addHandler(new HandlerA());
        chain.addHandler(new HandlerB());
        //执行处理
        chain.handle();
    }
}

第二版

上面的代码会有问题 如果不熟悉代码结构的人,定义一个handler很容易在handler方法 不能处理漏掉调用下一个处理器, 还有就是上面的handler方法存在重复 所以将调用代码抽象到父类

public abstract class Handler {
    protected Handler successor = null;

    public void setSuccessor(Handler successor) {
        this.successor = successor;
    }

    //定义在父类 final修饰不能重写
    public final void handle() {
        //调用 doHanle 由子类实现  模板模式
        boolean handled = doHandle();
        if (successor != null && !handled) {
            successor.handle();
        }
    }
    //抽象的定义 模板模式
    protected abstract boolean doHandle();
}

public class HandlerA extends Handler {
    /**
     * 只关注自身的处理逻辑
     * @return
     */
    @Override
    protected boolean doHandle() {
        boolean handled = false;
        //...
        return handled;
    }
}

public class HandlerB extends Handler {
    /**
     * 只关注自身的处理逻辑
     * @return
     */
    @Override
    protected boolean doHandle() {
        boolean handled = false;
        //...
        return handled;
    }
}

// HandlerChain和Application代码不变

第三版

采用非链表的方式来定义 采用数组的方式 使结构更简单

//定义handler
public interface IHandler {
    boolean handle();
}

//处理器a
public class HandlerA implements IHandler {
    @Override
    public boolean handle() {
        boolean handled = false;
        //...
        return handled;
    }
}

//处理器b

public class HandlerB implements IHandler {
    @Override
    public boolean handle() {
        boolean handled = false;
        //...
        return handled;
    }
}

public class HandlerChain {
    //通过集合维护处理器
    private List<IHandler> handlers = new ArrayList<>();

    public void addHandler(IHandler handler) {
        this.handlers.add(handler);
    }

    public void handle() {
        //遍历所有处理器 依次执行 直到其中一个能处理
        for (IHandler handler : handlers) {
            boolean handled = handler.handle();
            if (handled) {
                break;
            }
        }
    }
}

// 使用举例
public class Application {
    public static void main(String[] args) {
        HandlerChain chain = new HandlerChain();
        chain.addHandler(new HandlerA());
        chain.addHandler(new HandlerB());
        chain.handle();
    }
}

敏感字过滤实战

未使用设计模式

public class SensitiveWordFilter {
  // return true if content doesn't contain sensitive words.
  public boolean filter(Content content) {
    if (!filterSexyWord(content)) {
      return false;
    }

    if (!filterAdsWord(content)) {
      return false;
    }

    if (!filterPoliticalWord(content)) {
      return false;
    }

    return true;
  }

  private boolean filterSexyWord(Content content) {
    //....
  }

  private boolean filterAdsWord(Content content) {
    //...
  }

  private boolean filterPoliticalWord(Content content) {
    //...
  }
}

缺点 :如果需要增加一种过滤方式 就需要增加一个方法 和增加一个if判断 违反开闭原则

使用了设计模式

//抽象的过滤器
public interface SensitiveWordFilter {
    boolean doFilter(Content content);
}

/**
 * 涉黄过滤
 */
public class SexyWordFilter implements SensitiveWordFilter {
    @Override
    public boolean doFilter(Content content) {
        //是否包含敏感字
        boolean legal = true;
        //...
        return legal;
    }
}

// PoliticalWordFilter、AdsWordFilter类代码结构与SexyWordFilter类似

//责任链管理类
public class SensitiveWordFilterChain {
    private List<SensitiveWordFilter> filters = new ArrayList<>();

    public void addFilter(SensitiveWordFilter filter) {
        this.filters.add(filter);
    }

    // return true if content doesn't contain sensitive words.
    public boolean filter(Content content) {
        for (SensitiveWordFilter filter : filters) {
            if (!filter.doFilter(content)) {
                return false;
            }
        }
        return true;
    }
}

public class ApplicationDemo {
    public static void main(String[] args) {
        SensitiveWordFilterChain filterChain = new SensitiveWordFilterChain();
        filterChain.addFilter(new AdsWordFilter());
        filterChain.addFilter(new SexyWordFilter());
        filterChain.addFilter(new PoliticalWordFilter());
        //传入发表内容 判断是否可发表
        boolean legal = filterChain.filter(new Content());
        if (!legal) {
            // 不发表
        } else {
            // 发表
        }
    }
}

优点:如果需要增加一种过滤方式 只需要新增一个filter类 注册到chain 

源码中的应用

Servlet Filter

它可以实现对 HTTP 请求的过滤功能,比如鉴权、限流、记录日志、验证参数等等。因为它是 Servlet 规范的一部分,所以,只要是支持 Servlet 的 Web 容器(比如,Tomcat、Jetty 等),都支持过滤器功能

具体从ApplicationFilterChain 开始看

Spring MVC拦截器

具体从:HandlerExecutionChain开始看

 

posted @ 2020-04-15 15:53  意犹未尽  阅读(279)  评论(0编辑  收藏  举报