乐趣区

关于设计模式:设计模式学习笔记十六职责链模式

1 概述

1.1 引言

很多状况下,一个软件系统中能够解决某个申请的对象不知一个,比方洽购单的审批,主任,副董事长,董事长,董事会都能够解决洽购单,他们能够形成一条解决洽购单的链式构造,洽购单沿着这条链进行传递,这条链就叫职责链。

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

1.2 定义

职责链模式:防止将申请发送者与接收者耦合在一起,让多个对象都有机会接管申请,将这些对象连接成一条链,并且沿着这条链传递申请,直到有对象解决它为止。

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

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 注入,同时申明形象解决办法。

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);

接着调用对应的解决者解决即可。

3 实例

设计一个洽购单审批零碎,分级进行,依据金额不同由不同档次的人员审批,主任能够审批 5w 以下的洽购单,副董事长能够审批 5w-10w,董事长能够审批 10w-50w,50w 以上须要由董事会审批,应用职责链模式设计该零碎。

设计如下:

  • 形象解决者: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 总结

如果感觉文章难看,欢送点赞。

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

退出移动版