職責鏈設計模式是屬於經典設計模式中行爲型設計模式裏的一種設計模式。其實這種模式 在現實生活中不少地方出現,好比說: 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; } }
上面這種設計方式能夠處理完成相應的業務,但違反了:單一職責原則,開閉原則。一個類集中了過多的職責,若是一旦須要在期間進行擴展一個角色進行審批,就須要改動原有的代碼。而且這種設計模式是沒法實現使用方可定製化的,由於都寫死了。服務器
爲了解決上面設計的原則缺陷,咱們進行進行設計升級,把多個職責進行拆分,獨立出單個處理類。使用一個抽象的處理類,實現各個鏈節點的關聯與處理細節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
上面設計處理責任鏈模式處理採購單審批。請各位讀者採用職責鏈模式設計:標準鬥地主程序.對象