浅谈设计模式 - 责任链模式(十四)

简介: 浅谈设计模式 - 责任链模式(十四)

前言


这个模式基本是框架必备的一个设计模式,无论是netty还是spring,最为经典的aop也有体现这个设计模式,这个设计模式的学习难度不是很大,也比较容易看到具体的使用方式。


定义



责任链模式可以看作是对于请求和处理的解耦,比如框架之中常用的拦截器就是将请求和处理进行解耦,我们只要按照规范实现同样的接口,同时配置Bean之后就可以像刀片服务器一样“插入”我们自己定义的规则,由于我们设计不同的规则会有不同的拦截效果,所以这种设计模式是一种“行为型模式”。

关于责任链这个设计模式最为常见场景是类似校验,审核或者拦截处理,以及一些文本过滤等等工作的时候经常使用,下面我们来看下他的结构图是如何设计的:


优缺点


优点:


  1. 解耦了请求的处理者和发送者,处理者不需要关心发送者如何发送,只需要关注和处理自己的逻辑即可。
  2. 请求的处理顺序可以自由的定义和组合,提高了请求处理代码的复用性。


缺点:


  1. 责任链可能会丢失请求的处理者,因为责任链不知道谁是请求的处理者。
  2. 如果责任链过长过多,并且如果中间处理时间长,会影响整个请求和处理的效率
  3. 关键在于客户端的配置,如果客户端设置有误可能会产生莫名其妙的问题,比如编码处理之后进行字符处理,或者数据处理顺序不对等


第一种实现:统一调度



第一种实现较为简单,也是比较好理解的一种方式,这种处理方式有一点类似于注册监听器之后将请求分发给每一个监听者,


网络异常,图片无法展示
|


规范接口:规范接口比较常见的为handler()方法,由子类负责实现接口之后通过责任链调度中心进行调用,统一规范接口。

具体的处理对象:也就是上文所说的请求和处理接耦的的处理方,处理方不需要关心如果调用给

责任处理中心:主要负责责任链的内部调度和传递等等,当然也可以类似拦截处理。

客户端:注册相关的具体拦截处理对象,由责任处理中心统一处理,主要和客户端进行交互调度。

下面我们根据一个简单的加减乘除数字处理的调度器进行责任起模式的模板代码讲述。


请求处理接口:


请求处理接口定义了两个数字参数,同时返回处理结果


public interface Request {
   /**
    * 责任链的规范接口
    * @param val1 参数1
    * @param val1 参数2
    * @return
    */
   int process(int val1, int val2);
}


调度中心


责任链的调度中心主要负责请求的调度和处理,这里使用了数组的形式维护整个调度的过程。


public class RequestChain {
    private int index;
    private Request[] requestList;
    public RequestChain(int index) {
        this.index = 0;
        this.requestList = new Request[index];
    }
    public void addRequest(Request request) {
        if (index >= requestList.length) {
            throw new UnsupportedOperationException("已满,无法继续添加");
        }
        requestList[index++] = request;
    }
    public boolean process(int val1, int val2) {
        int result = 0;
        for (Request req : requestList) {
            try {
                result += req.process(val1, val2);
            } catch (Exception e) {
                System.out.printf("第%s处理失败,处理失败为%s%n", index, req);
                return false;
            }
        }
        System.out.printf("处理结果:%s\n", result);
        return true;
    }
}


具体实现


具体的实现方代码如下,下面是关于加除法和减法的相关处理:


public class DevideRequest implements Request{
    @Override
    public int process(int val1, int val2) {
        if(0 == val2){
            throw new IllegalArgumentException("除数不能为0");
        }
        return new BigDecimal(val1).divide(new BigDecimal(val2)).intValue();
    }
}


public class AddRequest implements Request{
    @Override
    public int process(int val1, int val2) {
        return val1 + val2;
    }
}


public class SubstractRequest implements Request {
    @Override
    public int process(int val1, int val2) {
        return val1 - val2;
    }
}


最后是单元测试的相关代码:


public class Main {
    public static void main(String[] args) {
        RequestChain requestChain = new RequestChain(3);
        requestChain.addRequest(new AddRequest());
        requestChain.addRequest(new SubstractRequest());
        requestChain.addRequest(new DevideRequest());
        requestChain.process(15, 6);
    }
}


这部分代码还是比较好理解一些, 下面我们来看下关于责任链模式存在一个“变化”的版本,主要的变动是在调用的处理中心使用类似链表的形式进行切换处理,具体的代码如下。


第二种实现:抽象处理者


抽象处理者和上面的分发形式略有不同,首先调度中心由单独的类改为抽象接口转抽象类的形式处理,通过定义抽象方法的形式,让下层的具体请求处理对象去处理下一次的转发对象。


网络异常,图片无法展示
|


责任链抽象调度中心:负责定义下层具体实现调度器的转发规则,以及定义统一的请求逻辑处理规范

具体处理调度对象:继承抽象调度中心的同时,需要调用调度中心的方法转发请求处理给下一个处理者,这样就实现了请求处理的转发操作,实现处理方法之后实现自己的处理逻辑。


抽象处理者


抽象处理者替代了责任调用中心,主要提供转发个下一个请求者的方法以及必须由具体实现者实现的一个抽象请求处理方法。


//抽象处理者角色
abstract class Handler {
    private Handler next;
    public void setNext(Handler next) {
        this.next = next;
    }
    public Handler getNext() {
        return next;
    }
    //处理请求的方法
    public abstract void handleRequest(String request);
}


具体实现


具体实现里面作为实现层需要将请求转发给下一个处理者,所以可以发现这样串联之后的请求处理方相互是清楚下一个处理者的,但是不清楚上一个处理者。


//具体处理者角色1
class ConcreteHandler1 extends Handler {
    public void handleRequest(String request) {
        if (request.equals("one")) {
            System.out.println("具体处理者1负责处理该请求!");
        } else {
            if (getNext() != null) {
                getNext().handleRequest(request);
            } else {
                System.out.println("没有人处理该请求!");
            }
        }
    }
}
//具体处理者角色2
class ConcreteHandler2 extends Handler {
    public void handleRequest(String request) {
        if (request.equals("two")) {
            System.out.println("具体处理者2负责处理该请求!");
        } else {
            if (getNext() != null) {
                getNext().handleRequest(request);
            } else {
                System.out.println("没有人处理该请求!");
            }
        }
    }
}


下面是具体的单元测试代码:


public class ChainOfResponsibilityPattern {
    public static void main(String[] args) {
        //组装责任链
        Handler handler1 = new ConcreteHandler1();
        Handler handler2 = new ConcreteHandler2();
        handler1.setNext(handler2);
        //提交请求
        handler1.handleRequest("two");
    }
}


总结


责任链模式自己编写的情况比较少,但是框架用的比较多,只要多熟悉和责任链模式有关的模版代码即可。


写在最后


常见的设计模式在过去的文章中讲述的差不多了,后续会讲述一些比较偏门的设计模式。

相关文章
|
8月前
|
【设计模式系列笔记】责任链模式
责任链模式是一种行为设计模式,它允许你将请求沿着处理者链进行传递,直到有一个处理者能够处理它。每个处理者都有一个对下一个处理者的引用。责任链模式常用于处理请求的场景,例如在一个请求需要经过多个步骤或者多个对象来处理的情况下。
99 0
浅谈设计模式 - 责任链模式(十四)
浅谈设计模式 - 责任链模式(十四)
78 0
浅谈设计模式 - 组合模式(十二)
浅谈设计模式 - 组合模式(十二)
97 0
浅谈设计模式 - 状态模式(十三)
浅谈设计模式 - 状态模式(十三)
46 0
深入浅出设计模式 - 责任链模式
深入浅出设计模式 - 责任链模式
9415 1
深入浅出设计模式 - 责任链模式
设计模式轻松学【十四】外观模式
生活中我们去餐馆吃饭,我们需要被接待,点菜,后台厨师准备菜品,做菜,服务员传送到桌上面,开始吃饭,吃完结账等等操作。但这一连串的操作中有些操作是不需要被我们关注的,比如厨师怎么做菜,怎么上菜,我们只需要点菜,吃饭,结账,所以我们可以引入外观模式来隐藏这些无需关注的细节。
140 0
设计模式轻松学【十四】外观模式
设计模式轻松学【十五】状态模式
在生活中,人的情绪往往都在变化,有高兴的时候和伤心的时候,不同的情绪有不同的行为,比如你开心的时候,会去大吃一顿,伤心的时候会出去唱K。外界也会影响我们的情绪,唱K之后你就变得开心了。 这个情绪的变化我们可以看成一个对象的状态变化,状态改变时会有不同的操作。对这种有状态的对象编程,传统的解决方案是:将这些所有可能发生的情况全都考虑到,然后使用 if-else 语句来做状态判断,再进行不同情况的处理。但当对象的状态很多时,程序会变得很复杂。这很像策略模式、但他们有着本质的区别。
95 0
设计模式轻松学【十五】状态模式
设计模式轻松学【十一】装饰模式
如果要扩展一些功能,我们可以采用装饰模式来实现。装饰者模式以对客户透明的方式动态地给一个对象附加上更多的责任。换言之,客户端并不会觉得对象在装饰前和装饰后有什么不同。装饰者模式可以在不使用创造更多子类的情况下,将对象的功能加以扩展。
145 0
设计模式轻松学【十一】装饰模式
AI助理

你好,我是AI助理

可以解答问题、推荐解决方案等