设计模式学习笔记(十六):职责链模式

1 概述

1.1 引言

不少状况下,一个软件系统中能够处理某个请求的对象不知一个,好比采购单的审批,主任,副董事长,董事长,董事会均可以处理采购单,他们能够构成一条处理采购单的链式结构,采购单沿着这条链进行传递,这条链就叫职责链。java

职责链能够是一条直线,一个环或者一个树形结构,最多见的职责链是直线型,即沿着一条单向的链来传递请求。链上的每个对象都是请求处理者,职责链模式能够将请求的处理者组织成一条链,并让请求沿着链传递,由链上的处理者对请求进行处理,客户端无须关系请求的处理细节以及具体的传递,只须要将请求发送到链上便可,实现请求发送者以及请求处理者的解耦。编程

1.2 定义

职责链模式:避免将请求发送者与接收者耦合在一块儿,让多个对象都有机会接收请求,将这些对象链接成一条链,而且沿着这条链传递请求,直到有对象处理它为止。微信

职责链模式是一种行为型模式。dom

1.3 结构图

在这里插入图片描述

1.4 角色

  • Handler(抽象处理者):定义一个处理请求的接口,通常为抽象类。由于每个处理者的下家仍是一个处理者,所以在抽象处理者中定义了一个抽象处理者的对象做为对下一个处理者的引用,经过该引用,处理者能够连成一条链
  • ConcreteHandler(具体处理者):抽象处理者的子类,实现具体处理方法,在处理前须要判断是否具备处理权限,若是拥有权限则处理,没有则转发到下一个处理者

2 典型实现

2.1 步骤

  • 定义抽象处理者:定义处理请求接口以及定义一个抽象处理者成员,做为下一个处理者的引用,通常为了让具体处理者方便调用,定义为protected
  • 定义具体处理者:处理/转发请求,处理请求前先判断是否具备权限 ,拥有则处理请求,不然转发请求
  • 客户端建立职责链:职责链模式并不建立职责链,职责链交由客户端建立,根据实际须要定义职责链顺序

2.2 抽象处理者

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

    public abstract void handleRequest(int num);
}

拥有一个设置下一处理者的对象,能够经过setter注入,同时声明抽象处理方法。ide

2.3 具体处理者

class ConcreteHandler1 extends Handler
{
    @Override    
    public void handleRequest(int num)
    {
        if(num < 10)
        {
            System.out.println("处理小于10的数字:"+num);
        }
        else
            successor.handleRequest(num);
    }
}

class ConcreteHandler2 extends Handler
{
    @Override    
    public void handleRequest(int num)
    {
        if(num < 20)
        {
            System.out.println("处理大于等于10且小于20的数字:"+num);
        }
        else
            successor.handleRequest(num);
    }
}

class ConcreteHandler3 extends Handler
{
    @Override    
    public void handleRequest(int num)
    {
        if(num < 30)
        {
            System.out.println("处理大于等于20且小于30的数字:"+num);
        }
        else
            successor.handleRequest(num);
    }
}

继承抽象处理者,首先判断是否拥有权限处理(这里是一个简单的if判断),若是有就处理,没有的话经过protected对象,也就是转发给下一个处理者处理。性能

2.4 客户端

public static void main(String[] args) 
{
    Handler handler = new ConcreteHandler1();
    Handler handler2 = new ConcreteHandler2();
    Handler handler3 = new ConcreteHandler3();
    handler.setSuccessor(handler2);
    handler2.setSuccessor(handler3);

    handler.handleRequest(3);
    handler.handleRequest(15);
    handler.handleRequest(22);
}

客户端针对抽象处理者编程,须要建立每个具体处理者对象,而且自定义职责链:测试

handler.setSuccessor(handler2);
handler2.setSuccessor(handler3);

接着调用对应的处理者处理便可。this

3 实例

设计一个采购单审批系统,分级进行,根据金额不一样由不一样层次的人员审批,主任能够审批5w如下的采购单,副董事长能够审批5w-10w,董事长能够审批10w-50w,50w以上须要由董事会审批,使用职责链模式设计该系统。

设计以下:spa

  • 抽象处理者:Approver
  • 具体处理者:Director+VicePresident+President+Congress
  • 采购单请求类:PurchaseRequest

代码以下:设计

//抽象处理者
abstract class Approver
{
    protected Approver successor;

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

    public abstract void processRequest(PurchaseRequest request);
}

//具体处理者:主任
class Director extends Approver
{
    @Override
    public void processRequest(PurchaseRequest request)
    {
        if(request.getAmount() < 50000)
            System.out.println("主任审批一笔\n金额为"+request.getAmount()+"\nid为"+request.getId()+"\n的采购单\n");
        else
            successor.processRequest(request);
    }
}

//具体处理者:副董事长
class VicePresident extends Approver
{
    @Override
    public void processRequest(PurchaseRequest request)
    {
        if(request.getAmount() < 100000)
            System.out.println("副董事长审批一笔\n金额为"+request.getAmount()+"\nid为"+request.getId()+"\n的采购单\n");
        else
            successor.processRequest(request);
    }
}

//具体处理者:董事长
class President extends Approver
{
    @Override
    public void processRequest(PurchaseRequest request)
    {
        if(request.getAmount() < 500000)
            System.out.println("董事长审批一笔\n金额为"+request.getAmount()+"\nid为"+request.getId()+"\n的采购单\n");
        else
            successor.processRequest(request);
    }
}

//具体处理者:董事会
class Congress extends Approver
{
    @Override
    public void processRequest(PurchaseRequest request)
    {
        System.out.println("董事会审批一笔\n金额为"+request.getAmount()+"\nid为"+request.getId()+"\n的采购单\n");
    }
}

//请求类:采购单
class PurchaseRequest
{
    private double amount;
    private String id;
    private static final String STR = "xcnvj232cvm";
    private static final Random random = new Random();

    public PurchaseRequest(double amount)
    {
        this.amount = amount;
        //简易的随机字符串
        this.id = STR.substring(0,random.nextInt(STR.length()-1)+1).repeat(random.nextInt(3)+2);
    }

    public double getAmount() {
        return this.amount;
    }

    public void setAmount(double amount) {
        this.amount = amount;
    }

    public String getId() {
        return this.id;
    }

    public void setId(String id) {
        this.id = id;
    }

}

测试:

public static void main(String[] args) 
{
    Approver director = new Director();
    Approver vicePresident = new VicePresident();
    Approver president = new President();
    Approver congress = new Congress();

    director.setSuccessor(vicePresident);
    vicePresident.setSuccessor(president);
    president.setSuccessor(congress);

    director.processRequest(new PurchaseRequest(12345));
    director.processRequest(new PurchaseRequest(54321));
    director.processRequest(new PurchaseRequest(123456));
    director.processRequest(new PurchaseRequest(654321));
}

输出以下:
在这里插入图片描述

4 分类

职责链模式能够分为纯的职责链模式与不纯的职责链模式。

4.1 纯的职责链模式

一个纯的职责链模式要求一个具体处理者对象只能在两个行为中选择一个,要么承担所有责任,要么将责任推给下家,不容许出现某一个具体处理者对象在承担了一部分或所有责任后又将责任向下传递的状况。

并且在纯的职责链模式中,要求一个请求必须被某一个处理者对象接收,不能出现某个请求未被任何一个处理者对象处理的状况,好比前面的采购单例子。

4.2 不纯的职责链模式

在一个不纯的职责链模式中,容许某个请求被一个具体处理者部分处理后再向下传递,或者一个具体处理者处理完某请求后其猴戏处理者能够继续处理该请求,并且一个请求能够最终不被任何处理者对象所接收。

在Java AWT 1.0中的事件处理模型应用就是不纯的职责链模式,基本原理以下:因为窗口组件通常位于容器组件中,当事件发生在窗口组件上时,先经过组件对象的handleEvent()方法传递给相应的事件处理方法,该事件处理方法将处理该事件,而后决定是否将该事件向上一级容器组件传播,上级容器组件在接到事件以后能够继续处理此事件并决定是否继续向上级容器组件传播,直到顶层容器组件为止。若是一直都没有处理方法则不处理该事件。

这种事件处理机制又叫事件浮升机制,JDK1.1后使用观察者模式来代理职责链模式处理事件。

5 主要优势

  • 下降耦合:职责链模式使得一个对象无须知道是其余哪个对象处理请求,对象仅需知道请求会被处理便可,接收者和发送者都没有对方明确信息,且链中对象不须要知道链的结构,由客户端负责链的建立,下降了系统耦合度
  • 简化对象链接:请求处理对象仅需维持一个指向其后继者的引用,而不须要维持它对全部候选处理者的引用,可简化对象的相互链接
  • 灵活的职责链:能够在运行时对链进行动态增长或者修改
  • 符合OCP:系统增长一个新的具体处理者时无须修改源码,只须要客户端重建职责链,符合OCP

6 主要缺点

  • 请求可能得不处处理:因为一个请求没有明确的接收者,所以请求不必定会被处理,也有可能由于职责链配置错误而得不处处理
  • 性能受到影响:对于较长的职责链,请求的处理可能涉及多个处理对象,系统性能会受到必定影响,并且代码调试时可能不方便
  • 死循环:若是职责链不当,可能会致使死循环调用

7 适用场景

  • 有多个对象能够处理同一个请求,具体哪一个对象处理该请求待运行时刻再肯定,客户端只需将请求提交到链上,而无须关心请求的处理对象是谁以及它是如何处理的
  • 在不明确指定接收者的状况下,向多个对象的一个提交一个请求
  • 可动态指定一组对象处理请求,客户端能够动态建立职责链来处理请求,还能够改变链中处理请求以及处理者之间的前后次序

8 总结

在这里插入图片描述

若是以为文章好看,欢迎点赞。

同时欢迎关注微信公众号:氷泠之路。

在这里插入图片描述

相关文章
相关标签/搜索