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

一、简介

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

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

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

二、模式实现

上面的两个场景我们调选一个进行实现,我们就用进阶的方式从最简单的设计一步一步往目标设计走。这里我选择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;
    }
}

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

升级设计

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

/**
 * @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;
    }
}

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

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

客户端调用

/**
 * @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;
    }
}

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

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

职责链模式优点

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

职责链模式缺点

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

合适使用场景

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

三、思考题

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

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章