设计模式-行为型-职责链设计模式

1、简介

职责链设计模式是属于经典设计模式中行为型设计模式里的一种设计模式。其实这种模式
在现实生活中不少地方出现,好比说:

1.多人打牌:
    上家出牌后,出牌请求到达下家,下家出牌后,下下家得到出牌机会, 在一轮后若是无人出牌,则能够从
    新下一轮出牌,这样一个场景,其实就是职责链模式的原型。

2.审批流程:
    再好比,一个公司的采购单审批流程,若是采购单总价在5万RMB,那么主任审核便可,    若是5-10万RMB
    由副董事长审批,10-50万由董事长审批,>=50万则由董事会审批。每个节点只负责职责内的订单额度,
    若是本身没有权限,则给本身的下节点进行转发申请。

2、模式实现

上面的两个场景咱们调选一个进行实现,咱们就用进阶的方式从最简单的设计一步一步往目标设计走。这里我选择2,审批流程的实现进行设计。初始代码以下:设计模式

原始设计

class AuditHandler {

    // @TODO 递交采购单给主任
    public void sendRequestToDirector(PurchaseRequest request) {
        if (request.getAmount() < 50000) {
            // @TODO 主任可审批该采购单
            this.handleByDirector(request);
        } else if (request.getAmount() < 100000) {
            // @TODO 副董事长可审批该采购单
            this.handleByVicePresident(request);
        } else if (request.getAmount() < 500000) {
            // @TODO 董事长可审批该采购单
            this.handleByPresident(request);
        } else {
            // @TODO 董事会可审批该采购单
            this.handleByCongress(request);
        }
    }

    // @TODO 主任审批采购单
    public void handleByDirector(PurchaseRequest request) {
        //代码省略
    }

    // @TODO 副董事长审批采购单
    public void handleByVicePresident(PurchaseRequest request) {
        //代码省略
    }

    // @TODO 董事长审批采购单
    public void handleByPresident(PurchaseRequest request) {
        //代码省略
    }

    // @TODO 董事会审批采购单
    public void handleByCongress(PurchaseRequest request) {
        //代码省略
    }
}

class PurchaseRequest {

    private long amount;

    public long getAmount() {
        return amount;
    }
}

上面这种设计方式能够处理完成相应的业务,但违反了:单一职责原则,开闭原则。一个类集中了过多的职责,若是一旦须要在期间进行扩展一个角色进行审批,就须要改动原有的代码。而且这种设计模式是没法实现使用方可定制化的,由于都写死了。服务器

升级设计

为了解决上面设计的原则缺陷,咱们进行进行设计升级,把多个职责进行拆分,独立出单个处理类。使用一个抽象的处理类,实现各个链节点的关联与处理细节ide

/**
 * @author chandlerHuang
 * @description @TODO 抽象处理类
 * @date 2020/3/27
 */
public abstract class AbstractHandler {

    // @TODO 处理链接
    protected AbstractHandler abstractHandler;

    public AbstractHandler(AbstractHandler abstractHandler) {
        this.abstractHandler = abstractHandler;
    }

    public void setAbstractHandler(AbstractHandler abstractHandler) {
        this.abstractHandler = abstractHandler;
    }

    public abstract void handle(PurchaseRequest request);
}

class Handler extends AbstractHandler{

    // 所指岗位
    private String position;

    // 处理金额上限
    private double amount;

    public void setPosition(String position) {
        this.position = position;
    }

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

    public Handler(AbstractHandler abstractHandler,String position, long amount) {
        super(abstractHandler);
        this.amount = amount;
        this.position = position;
    }

    @Override
    public void handle(PurchaseRequest request) {
        if(this.amount>request.getAmount()){
            // @TODO 处理请求
           System.out.println(this.position+"审核处理采购单:"+request.getNumber() +"->"+ request.getPurpose()+" 购买金额:"+request.getAmount());
        }else {
            // @TODO 交给下一节点处理
            this.abstractHandler.handle(request);
        }
    }
}

class PurchaseRequest {

    //采购金额
    private double amount;

    //采购单编号
    private int number;

    //采购目的、备注
    private String purpose;

    public PurchaseRequest(double amount, int number, String purpose) {
        this.amount = amount;
        this.number = number;
        this.purpose = purpose;
    }

    public double getAmount() {
        return amount;
    }

    public int getNumber() {
        return number;
    }

    public String getPurpose() {
        return purpose;
    }

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

    public void setNumber(int number) {
        this.number = number;
    }

    public void setPurpose(String purpose) {
        this.purpose = purpose;
    }
}

这里面对于责任链的构建是交给了使用方,这样极大的加强了这个设计的代码复用率,可扩展性以及流程的可变性。性能

这里咱们来演示一下使用方式,构建流程处理链。ui

客户端调用

/**
 * @author chandlerHuang
 * @description @TODO
 * @date 2020/3/27
 */
public class Test {

    public static void main(String[] args) {
        // @TODO 构建流程链
        Handler handler = init();

        // @TODO 构建采购单
        List<PurchaseRequest> requests = buildRequest();

        // @TODO 处理
        requests.forEach(request->{
            handler.handle(request);
        });
    }

    private static List<PurchaseRequest> buildRequest() {

        List<PurchaseRequest> datas = new ArrayList<>(4);
        PurchaseRequest data1 = new PurchaseRequest(39000.00,10001,"购买云服务器");

        PurchaseRequest data2 = new PurchaseRequest(89000.00,10002,"采购办公电脑与办公用品");

        PurchaseRequest data3 = new PurchaseRequest(490430.87,10003,"分公司装修装潢采购");

        PurchaseRequest data4 = new PurchaseRequest(1189490430,10004,"购置地皮建厂");

        datas.add(data1);
        datas.add(data2);
        datas.add(data3);
        datas.add(data4);

        return datas;
    }

    private static Handler init() {
        // 董事会节点
        Handler handler4 = new Handler(null,"董事会",Double.MAX_VALUE);
        // 董事长节点
        Handler handler3 = new Handler(handler4,"董事长",500000.00);
        // 副董事长节点
        Handler handler2 = new Handler(handler3,"副董事长", 100000.00);
        // 财务主任节点
        Handler handler = new Handler(handler2,"财务主任", 50000.00);
        return handler;
    }
}

设计模式-行为型-职责链设计模式

上面的代码显示了,若是你须要调整节点,只须要在构建流程链内处理(客户端|使用方),而咱们的设计方不须要进行改动,将发送方与处理方进行了解耦。无需关心具体处理节点。this

职责链模式优势

1.职责链模式使得一个对象无须知道是其余哪个对象处理其请求,对象仅需知道该请求会 被处理便可,接收者和发送者都没有对方的明确信息,且链中的对象不须要知道链的结构, 由客户端负责链的建立,下降了系统的耦合度。
2.请求处理对象仅需维持一个指向其后继者的引用,而不须要维持它对全部的候选处理者的 引用,可简化对象的相互链接。设计

职责链模式缺点

1.因为一个请求没有明确的接收者,那么就不能保证它必定会被处理,该请求可能一直到链 的末端都得不处处理;一个请求也可能因职责链没有被正确配置而得不处处理。
2.对于比较长的职责链,请求的处理可能涉及到多个处理对象,系统性能将受到必定影响, 并且在进行代码调试时不太方便。
3.若是建链不当,可能会形成循环调用,将致使系统陷入死循环。调试

合适使用场景

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

3、思考题

上面设计处理责任链模式处理采购单审批。请各位读者采用职责链模式设计:标准斗地主程序.对象

相关文章
相关标签/搜索