责任链模式(Chain of Responsibility Pattern) – 设计模式之行为模式

责任链模式(Chain of Responsibility Pattern) – 设计模式之行为模式:

 

目录

责任链模式(Chain of Responsibility Pattern)

类图

例子-审批:

过程:

类图:

代码:

状态 Approver

主管 Supervisor

经理 Manager

总监 Director

中间类

测试:

结果:

 例子-击鼓传花:

过程:

类图:

代码:

玩家 Player

玩家 PlayerA

玩家 PlayerB

玩家 PlayerC

玩家 PlayerD

玩家 PlayerE

测试:

结果:

总结:

使用场景

注意事项


责任链模式(Chain of Responsibility Pattern)

定义: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.

使多个对象都有机会处理请求,从而避免请求的发送者和接受者之间的耦合关系。将这个对象连成一条链,并沿着这条链传递该请求,直到有一个对象处理它为止。

 

类图

状态模式通用类图:

 

责任链模式的核心在“链”上,“链”是由多个处理者ConcreteHandler组成的

 

例子-审批:

过程:

  在工作中,员工出差等需要进行报销审批,审批需要通过主管,经理和总监进行审批。(PS:这里模拟审批状态的一个过程,也没有想到好的状态的一个例子,刚好责任链模式也用这个例子,可以做一个对比。)

 

类图:

 

代码:

状态 Approver

public abstract class Approver {

  protected String name;// 抽象出审批人的姓名

  protected Approver nextApprover;// 下一个审批人,下一个级别领导。

  public Approver(String name) {

    this.name = name;

  }

  public Approver setNextApprover(Approver nextApprover) {

    this.nextApprover = nextApprover;

    return this.nextApprover; // 返回下个审批人

  }

  public abstract void approve(int amount);

}

抽象的处理者实现三个职责:

  1,定义一个请求的处理方法approve,唯一对外开放的方法;

  2,定义一个链的编排方法setNext,设置下一个处理者;

  3,定义了具体的请求者必须实现的两个方法:定义名字和具体的处理任务。

注意 在责任链模式中一个请求发送到链中后,前一个节点消费部分消息,然后交由后续节点继续处理,最终可以有处理结果也可以没有处理结果

主管 Supervisor

public class Supervisor extends Approver {

  public Supervisor(String name) {

    super(name);

  }

  @Override

  public void approve(int amount) {

    if(amount <= 10000){

      System.out.println("主管"+name+"审批通过");

    }else{

      System.out.println("主管"+name+"无权审批,传送到经理那进行审批");

      this.nextApprover.approve(amount);

    }

  }

}

 

经理 Manager

public class Manager extends Approver {

  public Manager(String name) {

    super(name);

  }

  @Override

  public void approve(int amount) {

    if(amount <= 50000){

      System.out.println("经理"+name+"审批通过");

    }else{

      System.out.println("经理"+name+"无权审批,传送到总监那进行审批");

      this.nextApprover.approve(amount);

    }

  }

}

 

总监 Director

public class Director extends Approver {

  public Director(String name) {

    super(name);

  }

  @Override

  public void approve(int amount) {

    if(amount <= 100000){

      System.out.println("总监"+name+"审批通过");

    }else{

      System.out.println("一次性报销金额过大,请分批报销");

    }

  }

}

中间类

public class ApproveContext {

  Approver zhan = new Supervisor("张三");

  Approver li = new Manager("李四");

  Approver wang = new Director("王五");

  public ApproveContext() {

    zhan.setNextApprover(li);

    li.setNextApprover(wang);

  }

  public void approveNext(int amount){

    zhan.approve(amount);

  }

}

 

测试:

public class ApproveTest {

  public static void main(String[] args) {

    ApproveContext context = new ApproveContext();

    context.approveNext(1000);

    System.out.println("=========");

    context.approveNext(20000);

    System.out.println("=========");

    context.approveNext(60000);

    System.out.println("=========");

    context.approveNext(1100000);

  }

}

 

结果:

主管张三审批通过

=========

主管张三无权审批,传送到经理那进行审批

经理李四审批通过

=========

主管张三无权审批,传送到经理那进行审批

经理李四无权审批,传送到总监那进行审批

总监王五审批通过

=========

主管张三无权审批,传送到经理那进行审批

经理李四无权审批,传送到总监那进行审批

一次性报销金额过大,请分批报销

 

​​​​

 例子-击鼓传花:

过程:

  击鼓传花是一种热闹而又紧张的饮酒游戏,在酒宴上宾客依次坐定,由一人击鼓,开始击鼓时,花束就开始依次传递,鼓声一落,如果花束在谁手里,谁就开始饮酒了。在《红楼梦》中击鼓传花的故事,写一个例子

 

 

类图:

 

 

代码:

玩家 Player

public abstract class Player {

    protected String name; // 击鼓人

    private Player nextPlayer; // 传花人

    public Player(String name) {

        this.name = name;

    }

    //传入下一个具体的传花人

    protected Player setNextPlayer(Player nextPlayer) {

        this.nextPlayer = nextPlayer;

        return  this.nextPlayer;

    }

    //传递的过程

    public abstract void handle(int i);

    //传递給下一个

    public void nextPlayer(int index) {

        if (nextPlayer != null) {

            nextPlayer.handle(index);

        } else {

            System.out.println("这轮游戏结束!");

        }

    }

}

 

玩家 PlayerA

public class PlayerA extends Player {

    public PlayerA(String name) {

        super(name);

    }

    //传花的过程

    @Override

    public void handle(int i) {

        if (i == 1) {

            System.out.println(name+" 喝酒!");

        } else {

            System.out.println(name+"向下传花!");

            this.nextPlayer(i);

        }

    }

}

子类实现请求的处理,符合单一职责原则,各个实现类只完成一个动作或逻辑,也就是只有一个原因引起类的改变.

玩家 PlayerB

public class PlayerB extends Player {

    public PlayerB(String name) {

        super(name);

    }

    //传花的过程

    @Override

    public void handle(int i) {

        if (i == 2) {

            System.out.println(name+" 喝酒!");

        } else {

            System.out.println(name+"向下传花!");

            this.nextPlayer(i);

        }

    }

}

 

玩家 PlayerC

public class PlayerC extends Player {

    public PlayerC(String name) {

        super(name);

    }

    @Override

    public void handle(int i) {

        if (i == 3) {

            System.out.println(name+" 喝酒!");

        } else {

            System.out.println(name+"向下传花!");

            this.nextPlayer(i);

        }

    }

}

 

玩家 PlayerD

public class PlayerD extends Player {

    public PlayerD(String name) {

        super(name);

    }

    @Override

    public void handle(int i) {

        if (i == 4) {

            System.out.println(name+" 喝酒!");

        } else {

            System.out.println(name+"向下传花!");

            this.nextPlayer(i);

        }

    }

}

 

玩家 PlayerE

public class PlayerE extends Player {

    public PlayerE(String name) {

        super(name);

    }

    @Override

    public void handle(int i) {

        if (i == 4) {

            System.out.println(name+" 喝酒!");

        } else {

            System.out.println(name+"向下传花!");

            this.nextPlayer(i);

        }

    }

}

 

测试:

public class DrumBeaterTest {

    public static void main(String args[]) {

        PlayerA playerA = new PlayerA("贾母");

        PlayerB playerB = new PlayerB("贾赦");

        PlayerC playerC = new PlayerC("贾政");

        PlayerD playerD = new PlayerD("贾宝玉");

        PlayerE playerE = new PlayerE("贾环");

        playerA.setNextPlayer(playerB).setNextPlayer(playerC).setNextPlayer(playerD).setNextPlayer(playerE);

        int num;

        // 玩10轮

        for (int i = 0; i < 10; i++) {

            System.out.println("========== 第 "+(i+1)+"轮 ===========");

            num = (int) (Math.random()*(5)+1);

            playerA.handle(num);

        }

    }

}

 

结果:

========== 第 1轮 ===========

贾母 喝酒!

========== 第 2轮 ===========

贾母 喝酒!

========== 第 3轮 ===========

贾母 喝酒!

========== 第 4轮 ===========

贾母向下传花!

贾赦向下传花!

贾政向下传花!

贾宝玉 喝酒!

========== 第 5轮 ===========

贾母向下传花!

贾赦 喝酒!

========== 第 6轮 ===========

贾母向下传花!

贾赦 喝酒!

========== 第 7轮 ===========

贾母 喝酒!

========== 第 8轮 ===========

贾母向下传花!

贾赦 喝酒!

========== 第 9轮 ===========

贾母向下传花!

贾赦 喝酒!

========== 第 10轮 ===========

贾母 喝酒!

在实际应用中,一般会有一个封装类对责任模式进行封装,也就是替代Client类,直接返回链中的第一个处理者,具体链的设置不需要高层次模块关系,这样,更简化了高层次模块的调用,减少模块间的耦合,提高系统的灵活性。

 

总结:

优点: 

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

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

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

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

缺点: 

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

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

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

 

使用场景

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

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

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

注意事项

   链中节点数量需要控制,避免出现超长链的情况,一般的做法是在Handler中设置一个最大节点数量,在setNext方法中判断是否已经是超过其阈值,超过则不允许该链建立,避免无意识地破坏系统性能

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

天狼1222

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

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

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

打赏作者

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

抵扣说明:

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

余额充值