设计模式——行为型模式之借助责任链模式(Chain of Responsibility)灵活完成链式处理(五)

引言

在数据结构中有一种结构叫做 链表,从表头开始,通过下一节点的引用而连接起来形成一条链,每个节点可以断开再连接,结构比较灵活。如果把这种思想应用到编程中,构建这样的结构,那么每一个节点就可以映射为对象,每个对象都拥有一些共同的处理和独特处理逻辑,请求或提交从链头开始,逐一向下传递,直到这个请求被处理为止。正是基于这样的思想,前人提出了 责任链设计模型式。责任链模式很好的可以解决类似我们行政请假时,请假天数不同走的流程不同这样的场景。附行为型设计模式系列文章列表:

一、责任链模式概述

责任链模式(Chain of Responsibility)是一种结构简单的行为型模式,从一定程度上来说只有请求处理者对象这一种角色,其官方定义:使多个对象都有机会处理请求,从而避免了请求的发送者和接受者之间的耦合关系。将这些对象连成一条链,并沿着这条链传递该请求,直到有对象处理它为止(Avoid coupling the sender of a request to its receiver by giving more than one object a chance to handle the request.Chain the receiving objects and pass the request along the chain until an object handles it.)责任链模式的重点是在“链”上,由一条链去处理相似的请求在链中决定谁来处理这个请求,并返回相应的结果,使得多个处理对象有机会处理请求,从而实现请求发送者与请求接收者之间的解耦,把这些对象连成一条链,并把请求沿着这条链进行传递,直到完成请求的处理。请求发送者并不需要哪一个对象处理这个请求,因为总有一个请求接收者进行处理。在责任链模式中,由于请求的处理对象要形成一条链,所以每一个处理对象都要保存下一个处理对象的引用,在实际的应用中不宜拘泥于这种标准情况下,也可以是一个任务由链上的所有节点完成类似组装车间的模式总之,无论是学习任何模式都不能拘泥于所谓的标准,我这里是只举了一个例子,也不是说一定要这样做,要我说责任链的模式的核心思想在于“链”

二、责任链模式的优点和缺点及可用场景

1、责任链模式的优点

  • 责任链模式减低了发出命令的对象和处理命令的对象之间的耦合
  • 处理者对于请求者完全透明,请求者无需事先知道谁来处理
  • 它允许多与一个的处理者对象根据自己的逻辑来决定哪一个处理者最终处理这个命令,提高系统的扩展性。

2、责任链模式的缺点

  • 当责任链比较长时,所有的判定条件都要被执行一遍,性能问题比较严重。
  • 每个请求都是从链头遍历逐步到链尾,特别是在链比较长的时候,性能是一个非常大的问题。
  • 当环节比较多的时候,尤其是采取了类似递归的方式,调试的时候逻辑可能比较复杂。

3、责任链模式的可用场景

  • 多个对象可以处理同一请求,但具体由哪个对象处理,则需要动态决定时。
  • 在请求者不明确的情况下需要向多个对象中的一个提交请求时。
  • 需要动态的指定一组对象处理请求时。
  • 系统已经有一个由处理者对象组成的链。这个链可能由复合模式给出,
  • 当系统想发出一个请求给多个处理者对象中的某一个,但是不明显指定是哪一个处理者对象会处理此请求。
  • 当处理一个请求的处理者对象集合需要动态地指定时。

三、责任链模式的实现

这里写图片描述
责任链模式涉及到的主要角色如上图所示:

  • 抽象处理者(Handler)角色:定义出一个处理请求的接口(通常由一个Java抽象类或者Java接口实现)。如果需要,接口可以定义 出一个方法以设定和返回对下家的引用。上图中Handler类的聚合关系给出了具体子类对下家的引用,抽象方法handleRequest()规范了子类处理请求的操作。
  • 具体处理者(ConcreteHandler)角色:具体处理者接到请求后,可以选择将请求处理掉,或者将请求传给下家。由于具体处理者持有对下家的引用,因此,如果需要,具体处理者可以访问下家。

1、实现抽象处理对象

抽象处理对象一般需要完成:处理请求分发请求至下一节点

//抽象处理者角色,为了形成链式结构,必须持有下一个处理者的引用和拥有自己处理逻辑,甚至还可以持有上一个处理者的引用形成双向链表的结构
public abstract class AbstractHander {
    protected AbstractHander nextHander;
    /**
     * 
     * @param conditionStr 用于选择下一个处理者的条件字符串
     */
    public abstract void handle(String conditionStr);
    /**
     * 设置下一个处理者的引用
     * @param hander
     */
    public abstract  void setNextHander(AbstractHander hander);
}

2、实现具体处理对象

public class ConcreteHander extends AbstractHander {

    @Override
    public void handle(String conditionStr) {
        //如果传入的条件符合,则自己处理
        if("Hander".equals(conditionStr)){
            System.out.println("**条件符合,由ConcreteHander自己处理这个请求");
            return;
        }else{
            System.out.println("##条件不符合,由ConcreteHander转发这个请求到下一个处理者");
            if(nextHander!=null){
                nextHander.handle(conditionStr);//否则转到下一个处理者
            }
        }
    }

    @Override
    public void setNextHander(AbstractHander hander) {
        this.nextHander=hander;
    }

}
public class ConcreteHanderA extends AbstractHander {

    @Override
    public void handle(String conditionStr) {
        //如果传入的条件符合,则自己处理
        if("HanderA".equals(conditionStr)){
            System.out.println("**条件符合,由ConcreteHanderA自己处理这个请求");
            return;
        }else{
            System.out.println("##条件不符合,由ConcreteHanderA转发这个请求到下一个处理者");
            if(nextHander!=null){
                nextHander.handle(conditionStr);//否则转到下一个处理者
            }
        }
    }

    @Override
    public void setNextHander(AbstractHander hander) {
        this.nextHander=hander;
    }

}
public class ConcreteHanderB extends AbstractHander {

    @Override
    public void handle(String conditionStr) {
        //如果传入的条件符合,则自己处理
        if("HanderB".equals(conditionStr)){
            System.out.println("**条件符合,由ConcreteHanderB自己处理这个请求");
            return;
        }else{
            System.out.println("##条件不符合,由ConcreteHanderB转发这个请求到下一个处理者");
            if(nextHander!=null){
                nextHander.handle(conditionStr);//否则转到下一个处理者
            }
        }
    }
    @Override
    public void setNextHander(AbstractHander hander) {
        this.nextHander=hander;
    }

}

测试

public class ResponClicent {

    public static void main(String[] args) {
        //初始化 责任链
        ConcreteHander hander=new ConcreteHander();

        ConcreteHanderA handerA=new ConcreteHanderA();
        hander.setNextHander(handerA);
        ConcreteHanderB handerB=new ConcreteHanderB();
        handerA.setNextHander(handerB);

        hander.handle("HanderB");
    }
}

这里写图片描述

四、融合模板方法模式的升级版责任链模式

Java 的常见的23种模式中并不是完全独立的,在很多情况下都是可以互相结合使用,灵活的结合不同模式,才能更好提高的编码质量。在责任链模式中一个请求发送到链中后,前一节点消费部分消息,然后交由后续
节点继续处理,最终可以有处理结果也可以没有处理结果,也就是可以理解成每一个对象处理者在接到请求的时候,都需要按顺序先去判断是否有能力处理,那么通过融合模板方法模式,各个实现类只要关注的自己业务逻辑就成了,至于说什么事要自己处理,那就让父类去决定好了,也就是说父类实现了请求传递的功能,子类实现请求的处理,符合单一职责原则,各个实现类只完成一个动作或逻辑。接下来,以行政请假流程,假如请假2天以内,直接由直系领导批准,2天以上15天以内由部门领导批准为例:

1、封装各类对象

/**
 * 
 * @author Crazy.Mo
 * 请求的级别枚举类
 */
public enum Rank {
    DIRECT, DEPART,UNLEAGLE
}
public class ResonseResult {
    private String result;

    public ResonseResult(String result) {
        this.result = result;
    }

    public String getResult() {
        return result;
    }
}
public class MyRequest {
    private Rank rank;
    private int days;
    private String content;

    public MyRequest(int day , String content) {
        super();
        this.days = day;
        this.content = content;
    }

    public Rank getRank() {
        //这里预定义了2天以内直接由直系领导申请
        if(days>0&&days<=2){
            this.rank=Rank.DIRECT;
        }else if(days>2&&days<=15){
            this.rank=Rank.DEPART;
        }else{
            this.rank=Rank.UNLEAGLE;
        }
        return this.rank;
    }

    public String getContent(){
        return this.content;
    }

    public int getDays() {
        return days;
    }
}

2、实现抽象处理对象

在抽象处理对象中结合模板方法模式,先判断请假请求是哪个级别

ackage responsibilitymethod;

public abstract class AbstractLeader {
    private AbstractLeader nextLeader;

    /**
     * 每个处理者都必须对请求做出处理
     */
    public final ResonseResult handleMessage(MyRequest myRequest) {
        ResonseResult ResonseResult = null;
        // 判断是否是自己的处理级别
        if (myRequest.getDays()<=limitDay()&&(this.getLeaderRank().equals(myRequest.getRank()))) {
            ResonseResult = this.handle(myRequest);
        } else { // 不属于自己的处理级别
            // 判断是否有下一个处理者
            if (this.nextLeader != null) {
                System.out.println("当前级别无法处理,传递到下一级");
                ResonseResult = this.nextLeader.handleMessage(myRequest);
            } else {
                // 没有适当的处理者,业务自行处理
                System.out.println("没有适当的处理者,业务无法处理");
            }
        }
        return ResonseResult;
    }

    /**
     * 设置下一个处理者
     */
    public void setNext(AbstractLeader nextLeader) {
        this.nextLeader = nextLeader;
    }

    /**
     * 每个处理者都有一个处理级别
     * @return
     */
    protected abstract Rank getLeaderRank();

    /**
     * 每个处理者都必须实现处理任务的逻辑
     */
    protected abstract ResonseResult handle(MyRequest myrequest);

    protected abstract int limitDay();
}

3、实现具体处理者对象

public class DirectLeader extends AbstractLeader {

    @Override
    protected Rank getLeaderRank() {
        return Rank.DIRECT;
    }

    @Override
    protected ResonseResult handle(MyRequest myrequest) {
        return new ResonseResult(myrequest.getContent()+"已处理成功,直系领导已经批准,流程结束");
    }

    @Override
    protected int limitDay() {
        return 2;
    }

}

public class DepartLeader extends AbstractLeader {

    @Override
    protected Rank getLeaderRank() {
        return Rank.DEPART;
    }

    @Override
    protected ResonseResult handle(MyRequest myrequest) {
        return new ResonseResult(myrequest.getContent()+"已处理成功,部门领导已经批准,流程结束");
    }

    @Override
    protected int limitDay() {
        return 15;
    }

}

4、测试

public class ResponClient {

    public static void main(String[] args) {
        AbstractLeader handler1 = new DirectLeader();
        AbstractLeader handler2 = new DepartLeader();

        handler1.setNext(handler2);
        //提交请求,返回结果
        System.out.println(handler1.handleMessage(new MyRequest(10,"因身体不舒服请假10天")).getResult());

        System.out.println(handler1.handleMessage(new MyRequest(1,"因事请假1天")).getResult());
    }

}

这里写图片描述

小结

发送者不需要知道接收者的具体信息,只要交给一个接收者就可以了。降低了客户与系统的耦合程度对于每一个具体的处理对象来讲,它只需要保存其下一个处理对象的引用就可以了,这样就使得处理对象之间的耦合度降低责任链的结构是在客户端定义的,这就使得可以随时增加或者修改责任链的结构,增强了指派责任的灵活性。
源码传送门

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

CrazyMo_

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值