设计模式(14):责任链模式及其在Java中的典型应用示例

责任链模式及其在Java中的典型应用实例

1、什么是责任链模式

2、责任链模式的特性

3、责任链模式的优缺点及其应用场景

4、责任链模式的应用示例

5、责任链模式在Java中的典型应用示例


1、什么是责任链模式

责任链模式定义:为请求创建了一个接收者对象的链。这种模式给予请求的类型,对请求的发送者和接收者进行解耦。这种类型的设计模式属于行为型模式。在这种模式中,通常每个接收者都包含对另一个接收者的引用。如果一个对象不能处理请求,那么它会把相同的请求传给下一个接收者,以此类推。

2、责任链模式的特性

(1)意图:

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

(2)主要解决:

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

(3)何时使用:

在处理消息的时候以过滤很多道。

(4)如何解决:

拦截的类都实现统一接口。

(5)关键代码:

Handler 里面聚合它自己,在 HandlerRequest 里判断是否合适,如果没达到条件则向下传递,向谁传递之前 set 进去。

3、责任链模式的优缺点及其应用场景

(1)优点: 

1)降低耦合度。它将请求的发送者和接收者解耦。

2)简化了对象。使得对象不需要知道链的结构。

3)增强给对象指派职责的灵活性。通过改变链内的成员或者调动它们的次序,允许动态地新增或者删除责任。

4)增加新的请求处理类很方便。

(2)缺点: 

1)不能保证请求一定被接收。

2)系统性能将受到一定影响,而且在进行代码调试时不太方便,可能会造成循环调用。

3)可能不容易观察运行时的特征,有碍于除错。

(3)使用场景:

1)有多个对象可以处理同一个请求,具体哪个对象处理该请求由运行时刻自动确定。

2)在不明确指定接收者的情况下,向多个对象中的一个提交一个请求。

3)可动态指定一组对象处理请求。

(4)注意事项:

在 JAVA WEB 中遇到很多应用。

4、责任链模式的应用示例

(1)示例场景:

服务器后端在对前端发送过来的请求进行处理的时候,一般的一个简单的过滤认证行为为: Request—>请求频率验证—>登录认证—>访问权限—>敏感词过滤—>... 我们可以直接在程序代码中进行顺序流程代码编写,但这样的代码耦合不易于扩展维护和复用,我们可以使用责任链的形式来实现, 责任链模式主要可以采用链表的形式进行实现。

(2)代码示例:

定义一个请求包装类,其中该类里面使用建造者模式来创建对象(这里只是实现示例,可不使用建造者模式):

//定义一个请求包装类
class Request{
    //模拟一些请求验证操作
    private boolean loggedOn;
    private boolean frequentOk;
    private boolean isPermits;
    private boolean containSensitiveWords;
    private String requestBody;

    private Request(boolean loggedOn, boolean frequentOk, boolean isPermits, boolean containSensitiveWords) {
        this.loggedOn = loggedOn;
        this.frequentOk = frequentOk;
        this.isPermits = isPermits;
        this.containSensitiveWords = containSensitiveWords;
    }

    //使用建造者模式创建对象
    static class RequestBuilder{
        private boolean loggedOn;
        private boolean frequentOk;
        private boolean isPermits;
        private boolean containsSensitiveWords;

        RequestBuilder loggedOn(boolean loggedOn){
            this.loggedOn = loggedOn;
            return this;
        }

        RequestBuilder frequentOk(boolean frequentOk){
            this.frequentOk = frequentOk;
            return this;
        }

        RequestBuilder isPermits(boolean isPermits){
            this.isPermits = isPermits;
            return this;
        }
        RequestBuilder containsSensitiveWords(boolean containsSensitiveWords){
            this.containsSensitiveWords = containsSensitiveWords;
            return this;
        }

        public Request build(){
            Request request = new Request(loggedOn,frequentOk,isPermits,containsSensitiveWords);
            return request;
        }
     }

     public boolean isLoggedOn(){
        return loggedOn;
     }
     public boolean isFrequentOk(){
        return frequentOk;
     }
     public boolean isPermits(){
        return isPermits;
     }
     public boolean isContainSensitiveWords(){
        return containSensitiveWords;
     }
}

进行责任链抽象,通过链表形式来实现:

//使用链表形式来实现责任链,责任链抽象
abstract class Handler{
    //责任链的下一个节点
    Handler next;

    public Handler(Handler next) {
        this.next = next;
    }

    public Handler getNext() {
        return next;
    }

    public void setNext(Handler next) {
        this.next = next;
    }
    //每个节点都需要处理请求
    abstract boolean process(Request request);
}

定义责任链的业务主体子类,可以有多个:这里以访问频率验证和登录验证为例:

//责任链的具体子类
class RequestFrequentHandler extends Handler{
    public RequestFrequentHandler(Handler next) {
        super(next);
    }

    @Override
    boolean process(Request request) {
        //业务代码
        System.out.println("访问频率控制.");
        if(request.isFrequentOk()){
            //访问正常,传递给责任链的下一个节点
            Handler next = getNext();
            if(null == next){
                return true;
            }
            if(!next.process(request)){
                return false;
            }else{
                return true;
            }
        }
        return false;
    }
}

//登录的处理器
class LoggingHandler extends Handler{
    public LoggingHandler(Handler next) {
        super(next);
    }

    @Override
    boolean process(Request request) {
        System.out.println("登录验证...");
        if(request.isLoggedOn()){
            Handler next = getNext();
            if(null==next){
                return true;
            }
            if(!next.process(request)){
                return false;
            }else{
                return true;
            }
        }
        return false;
    }
}

使用示例:这里我们通过构造使用责任链来进行,对于一个请求,先进行访问频率验证,再进行登录验证,如果有一个验证不通过,则返回异常。链式执行,依次调用....

public class ChainOfResponsibilityTest {
    public static void main(String[] args) {
        //测试示例
        //构造请求
        Request request = new Request.RequestBuilder().frequentOk(true).loggedOn(true).build();
        //构造责任链
        RequestFrequentHandler requestFrequentHandler = new RequestFrequentHandler(new LoggingHandler(null));
        //测试责任链处理流程、结果
        if(requestFrequentHandler.process(request)){
            System.out.println("正常业务处理...");
        }else{
            System.out.println("访问异常...");
        }
    }
}

 测试结果输出示例:

访问频率控制.
登录验证...
正常业务处理...

这里当我们把模拟请求修改为:frequentOk(false)时:

public class ChainOfResponsibilityTest {
    public static void main(String[] args) {
        //测试示例
        //构造请求
        Request request = new Request.RequestBuilder().frequentOk(false).loggedOn(true).build();
        //构造责任链
        RequestFrequentHandler requestFrequentHandler = new RequestFrequentHandler(new LoggingHandler(null));
        //测试责任链处理流程、结果
        if(requestFrequentHandler.process(request)){
            System.out.println("正常业务处理...");
        }else{
            System.out.println("访问异常...");
        }
    }
}

输出结果为: 

访问频率控制.
访问异常...

说明程序时链式顺序执行的,当出现出现某个链式节点验证不通过返回false时,后续链上节点将不执行。

5、责任链模式在Java中的典型应用示例

在Java中,Servlet容器是责任链模式的经典应用。如在tomcat的包中,带有Filter、FilterChain结尾的类都是使用的是责任链模式。

(1)javax.servlet.Filter类使用的就是责任链模式来实现对请求的过滤,过滤器是一个对象,执行在任一请求到资源(servlet或静态内容)过滤任务,或者从一个资源,或两者的响应。源码如下:

public interface Filter {

   
    public default void init(FilterConfig filterConfig) throws ServletException {}

    /**
     * The <code>doFilter</code> method of the Filter is called by the container
     * each time a request/response pair is passed through the chain due to a
     * client request for a resource at the end of the chain. The FilterChain
     * passed in to this method allows the Filter to pass on the request and
     * response to the next entity in the chain.
     * <p>
     * A typical implementation of this method would follow the following
     * pattern:- <br>
     * 1. Examine the request<br>
     * 2. Optionally wrap the request object with a custom implementation to
     * filter content or headers for input filtering <br>
     * 3. Optionally wrap the response object with a custom implementation to
     * filter content or headers for output filtering <br>
     * 4. a) <strong>Either</strong> invoke the next entity in the chain using
     * the FilterChain object (<code>chain.doFilter()</code>), <br>
     * 4. b) <strong>or</strong> not pass on the request/response pair to the
     * next entity in the filter chain to block the request processing<br>
     * 5. Directly set headers on the response after invocation of the next
     * entity in the filter chain.
     *
     * @param request  The request to process
     * @param response The response associated with the request
     * @param chain    Provides access to the next filter in the chain for this
     *                 filter to pass the request and response to for further
     *                 processing
     *
     * @throws IOException if an I/O error occurs during this filter's
     *                     processing of the request
     * @throws ServletException if the processing fails for any other reason
     */
    public void doFilter(ServletRequest request, ServletResponse response,
            FilterChain chain) throws IOException, ServletException;

    
    public default void destroy() {}
}

(2)javax.Servlet.FilterChain类也是通过责任链模式来进行过滤链中过滤器的调用

public interface FilterChain {

    /**
     * Causes the next filter in the chain to be invoked, or if the calling
     * filter is the last filter in the chain, causes the resource at the end of
     * the chain to be invoked.
     *
     * @param request
     *            the request to pass along the chain.
     * @param response
     *            the response to pass along the chain.
     *
     * @throws IOException if an I/O error occurs during the processing of the
     *                     request
     * @throws ServletException if the processing fails for any other reason

     * @since 2.3
     */
    public void doFilter(ServletRequest request, ServletResponse response)
            throws IOException, ServletException;

}

FilterChain是Servlet容器提供给开发人员的对象,它提供了对资源的已过滤请求的调用链的视图。过滤器使用FilterChain调用链中的下一个过滤器,或者调用过滤器是链中的最后一个过滤器,用于在链的末端。

 

 

本文源代码:

https://github.com/JianfuYang/2020-yjf-review/tree/master/src/designpatterns/responsibility

 

声明:本文部分内容整理来源于网络,仅做个人学习使用!侵删~

本文部分内容参考链接:

https://www.runoob.com/design-pattern/chain-of-responsibility-pattern.html

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Java迭代器模式的应用非常广泛,以下是一些常见的使用场景: 1. 遍历集合类的元素,如ArrayList、LinkedList、HashSet、TreeSet等。 2. 遍历Map的键值对,如HashMap、TreeMap等。 3. 遍历文件的数据,如BufferedReader等。 下面是一个简单的示例代码,演示了如何使用Java的迭代器模式来遍历ArrayList的元素: ```java import java.util.ArrayList; import java.util.Iterator; public class IteratorDemo { public static void main(String[] args) { ArrayList<String> list = new ArrayList<>(); list.add("Java"); list.add("Python"); list.add("C++"); Iterator<String> it = list.iterator(); while (it.hasNext()) { String s = it.next(); System.out.println(s); } } } ``` 在上面的代码,我们首先创建了一个ArrayList对象,并向其添加了三个元素。然后,我们通过调用list.iterator()方法获取了一个迭代器对象it,并使用while循环遍历ArrayList的元素。在循环体,我们通过it.next()方法获取了下一个元素,并将其打印出来。 Java的迭代器模式的源码实现非常复杂,具体实现方式与不同的集合类有关。以ArrayList为例,其迭代器实现类是Itr,代码如下: ```java private class Itr implements Iterator<E> { int cursor; // 下一个要返回的元素的索引 int lastRet = -1; // 上一个返回的元素的索引,初始值为-1 int expectedModCount = modCount; // ArrayList的修改次数 public boolean hasNext() { return cursor != size; // 判断是否还有下一个元素 } @SuppressWarnings("unchecked") public E next() { checkForComodification(); // 检查ArrayList是否被修改 int i = cursor; if (i >= size) throw new NoSuchElementException(); Object[] elementData = ArrayList.this.elementData; if (i >= elementData.length) throw new ConcurrentModificationException(); cursor = i + 1; return (E) elementData[lastRet = i]; } public void remove() { if (lastRet < 0) throw new IllegalStateException(); checkForComodification(); // 检查ArrayList是否被修改 try { ArrayList.this.remove(lastRet); cursor = lastRet; lastRet = -1; expectedModCount = modCount; } catch (IndexOutOfBoundsException ex) { throw new ConcurrentModificationException(); } } final void checkForComodification() { if (modCount != expectedModCount) throw new ConcurrentModificationException(); } } ``` 在上面的代码,我们可以看到Itr类实现了Iterator接口,其包含了hasNext()、next()、remove()等方法。在next()方法,我们首先检查ArrayList是否被修改,然后获取下一个元素的索引,并返回该元素。在remove()方法,我们首先检查上一个返回的元素的索引是否合法,然后调用ArrayList的remove()方法删除该元素。在以上代码,还包含了一些用于检查ArrayList是否被修改的方法,以确保迭代器的正确性。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值