設計模式是什么鬼(責任鏈)


  • //本文作者:凸凹里歐
  • //本文收錄菜單欄:《設計模式是什么鬼》專欄中

 

曾經有這么一些零散的功能節點,他們各自承擔各自的義務,分工明確,各司其職。為了更高效,更完整地解決客戶的問題,他們發揚團隊精神,互相串聯起來形成一個有序的責任傳遞鏈表,於是責任鏈模式誕生了。當然,它的結構也不一定非得是鏈表,甚至可以是樹型分叉結構,這要根據業務場景看怎樣去靈活運用,但其核心意義是為了處理某種連續的流程,並確保業務一定能走到相應的責任節點上並得到相應的處理。

 

說到這里想必大家已經想到了工作流吧?對,企事業單位中通常為了完成某項日常任務,通常要制定一些工作流程,按步驟拆分,並組織好各個環節中的邏輯關系及走向,這樣才能更高效、更規范地完成任務。

 

根據以上流程圖,我們來做一個最簡單的例子。假設某公司針對出差報銷業務制定審批流程,有三個審批角色分別是員工(1000元權限)、經理(5000元權限)、以及CEO(10000元權限),各審批人代碼如下。

public class Staff {

    private String name;

    public Staff(String name) {
        this.name = name;
    }

    public boolean approve(int amount) {
        if (amount <= 1000) {
            System.out.println("審批通過。【員工:" + name + "】");
            return true;
        } else {
            System.out.println("無權審批,請找上級。【員工:" + name + "】");
            return false;
        }
    }

}

  

public class Manager {

    private String name;

    public Manager(String name) {
        this.name = name;
    }

    public boolean approve(int amount) {
        if (amount <= 5000) {
            System.out.println("審批通過。【經理:" + name + "】");
            return true;
        } else {
            System.out.println("無權審批,請找上級。【經理:" + name + "】");
            return false;
        }
    }

}
 
        
public class CEO {

    private String name;

    public CEO(String name) {
        this.name = name;
    }

    public boolean approve(int amount) {
        if (amount <= 10000) {
            System.out.println("審批通過。【CEO:" + name + "】");
            return true;
        } else {
            System.out.println("駁回申請。【CEO:" + name + "】");
            return false;
        }
    }

}

 

好了,審批人們定義完畢,邏輯非常簡單縝密,如果超過審批金額最大權限則打回去,開始寫申請人客戶端類。

 

public class Client {
    public static void main(String[] args) {
        int amount = 10000;//出差花費10000元
        // 先找員工張飛審批
        Staff staff = new Staff("張飛");
        if (!staff.approve(amount)) {
            //被拒,找關二爺問問。
            Manager manager = new Manager("關羽");
            if (!manager.approve(amount)) {
                //還是被拒,只能找老大了。
                CEO ceo = new CEO("劉備");
                ceo.approve(amount);
            }
        }
        /***********************
        無權審批,請找上級。【員工:張飛】
        無權審批,請找上級。【經理:關羽】
        審批通過。【CEO:劉備】
        ***********************/
    }
}

  

功夫不負有心人,跑了三個地方找了三個人,一萬元的大額報銷單終於被大老板審批了。然而,大家有沒有發現問題?我們走的審批流程好像有點過於復雜了,找這個不行那個不同意,跑來跑去的好像自己有點像是被踢皮球的感覺。此外,如果我們后期要優化完善此工作流程,或是添加新的審批角色進來,那就得不停地修改此處的邏輯,最終的修改結果會是?

 

 

亂了,全亂套了,我們終將被淹沒在一堆復雜的審批流程中,跑斷腿也找不到門路。這顯然是違反設計模式原則的,我們必須進行重構。我們觀察此類中的審批邏輯,這顯然就是一個鏈式結構,審批人之間環環相扣,對於自己無法處理的申請,會像被踢皮球似的傳給上級,直到某人解決此申請,對員工張飛來說,他只知道自己傳球給關羽了,僅此而已。

 

進一步分析,審批人肯定是不同的角色,並且每個角色的審批邏輯會有區別,所以我們得把這些角色的審批邏輯分開來寫,對每個角色的責任范圍我們進行定義,我只懂自己怎么審批(責任),我處理不了的我遞交給上層(鏈條),開始重構,先抽象出一個審批人類。

 

public abstract class Approver {// 審批人抽象類

    protected String name;// 抽象出審批人的姓名。
    protected Approver nextApprover;// 下一個審批人,更高級別領導。

    public Approver(String name) {
        this.name = name;
    }

    protected Approver setNextApprover(Approver nextApprover) {
        this.nextApprover = nextApprover;
        return this.nextApprover;// 返回下個審批人,鏈式編程。
    }

    public abstract void approve(int amount);// 抽象審批方法由具體審批人子類實現
}

  

注意第4行,審批人只認識自己的領導,所以會持有下一級領導的引用,同時第10行的代碼用於把領導注入進來。第15行是我們的審批方法了,但每個角色審批邏輯會有區別,所以這里進行抽象,並由具體的審批角色子類去實現,先從員工看起。

 

public class Staff extends Approver {

    public Staff(String name) {
        super(name);
    }

    @Override
    public void approve(int amount) {
        if (amount <= 1000) {
            System.out.println("審批通過。【員工:" + name + "】");
        } else {
            System.out.println("無權審批,升級處理。【員工:" + name + "】");
            this.nextApprover.approve(amount);
        }
    }

}

 

很簡單,員工類繼承了審批角色類,第9行申明審批權限為1000元,重點在於第13行這里調用了自己上級領導的審批方法,顯然這里是自己處理不了的申請單了。大同小異,再重構經理及CEO審批角色類。

 

public class Manager extends Approver {

    public Manager(String name) {
        super(name);
    }

    @Override
    public void approve(int amount) {
        if (amount <= 5000) {
            System.out.println("審批通過。【經理:" + name + "】");
        } else {
            System.out.println("無權審批,升級處理。【經理:" + name + "】");
            this.nextApprover.approve(amount);
        }
    }

}
public class CEO extends Approver {

    public CEO(String name) {
        super(name);
    }

    @Override
    public void approve(int amount) {
        if (amount <= 10000) {
            System.out.println("審批通過。【CEO:" + name + "】");
        } else {
            System.out.println("駁回申請。【CEO:" + name + "】");
        }
    }

}

 

CEO類作為鏈條的尾巴,也就是最高級別,第12行的越權邏輯會最終拒絕申請單。很簡單吧?我們生成一下這個鏈條,並從員工開始傳遞申請單。

 

public class Client {
    public static void main(String[] args) {
        Approver flightJohn = new Staff("張飛");
        flightJohn.setNextApprover(new Manager("關羽")).setNextApprover(new CEO("劉備"));

        //高層接觸不到也沒必要接觸,直接找員工張飛審批。
        flightJohn.approve(1000);
        /***********************
        審批通過。【員工:張飛】
        ***********************/

        flightJohn.approve(4000);
        /***********************
        無權審批,升級處理。【員工:張飛】
        審批通過。【經理:關羽】
        ***********************/

        flightJohn.approve(9000);
        /***********************
        無權審批,升級處理。【員工:張飛】
        無權審批,升級處理。【經理:關羽】
        審批通過。【CEO:劉備】
        ***********************/

        flightJohn.approve(88000);
        /***********************
        無權審批,升級處理。【員工:張飛】
        無權審批,升級處理。【經理:關羽】
        駁回申請。【CEO:劉備】
        ***********************/
    }
}
 
        

這里注意第4行的代碼對責任鏈進行構造(其實這里我們還可以交由工作流工廠去構造完成,讀者可以自己實踐練習),從員工開始一直到CEO結束。之后的業務就非常簡單了,直接遞單給員工張飛,審批流程便魔法般地啟動了,審批單在這個責任鏈條上層層遞交,最終給出結果。

 

至此,申請人與審批人實現了解耦,我們只需遞單送給責任鏈即可,申請人不必再關心每個處理細節,只需交給接口人張飛處理就妥了。使用了責任鏈模式后的代碼看起來非常簡潔,各個角色的責任划分非常明確並且被分開定義到了每個角色類中,再把他們串起來去調用,一氣呵成。后期如果再繼續添加新的角色只需要添加新角色類並加入鏈條即可,鏈條的隨意伸縮,靈活的可伸縮性,完美的可擴展性。掛上這條鈦合金項鏈,維護世界和平的責任就交給你了!

 

 

在實際應用中,我們切勿生搬硬套,還需根據實際需求場景進行靈活運用,就拿工業現代化生產線舉例,這個其實也類似責任鏈模式,但不同之處在於其組裝工作是必須經過每個組裝節點處理的,從頭到尾的全鏈處理而不能中途退出,讀者朋友可以自己寫代碼練習,實踐與思考要相結合並循環往復,二者都非常重要。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM