軟件設計模式學習(十七)職責鏈模式


系統中如果存在多個對象可以處理一個同一請求,可以通過職責鏈模式將這些處理請求的對象連成一條鏈,讓請求沿着該鏈進行傳遞。如果鏈上的對象可以處理該請求則進行處理,否則將請求轉發給下家處理


模式動機

很多情況下,可以處理某個請求的對象不止一個,如大學裏的獎學金審批,學生先向輔導員提交審批表,輔導員簽字審批後再交給系主任簽字審批,接着是院長審批,最後可能是校長審批,在這個過程中,獎學金申請表可以看作一個請求對象,不同級別審批者都可以處理該請求,除了輔導員之外,學生不需一一和其他審批者交互,只需等待結果即可。審批過程中如果某一審批者認爲不符合條件,則請求中止,否則將請求傳遞給下一審批者,最後由校長拍板。

在這個過程中,輔導員、系主任、院長、校長構成一條鏈,申請表沿着這條鏈傳遞,就叫職責鏈。職責鏈可以是一條直線、一個環或一個樹形結構,常見的職責鏈是直線型。請求沿着鏈傳遞,由鏈上的處理者對請求進行處理,客戶無須關心請求的處理和傳遞細節,實現請求發送者和請求處理者解耦。


模式定義

避免請求者與接收者耦合在一起,讓多個對象都有可能接受請求,將這些對象連接成一條鏈,並且沿着這條鏈傳遞請求,直到有對象處理爲止。職責鏈模式也叫責任鏈模式,它是一種對象行爲型模式。


模式結構

在這裏插入圖片描述

  1. Handler(抽象處理者)

    定義了一個處理請求的接口,由於不同的具體處理者處理請求方式不同,因此在其中定義抽象請求處理方法。在抽象處理者中定義一個自類型(抽象處理者類型)的對象,作爲對下家的引用。

  2. ConcreteHandler(具體處理者)

    具體處理者是抽象處理者子類,實現抽象請求處理方法,處理用戶請求。在處理請求之前要進行判斷,看是否具有相應處理權限,如果可以處理就處理,否則將請求轉發給後繼者。

  3. Client(客戶類)

    用於向鏈中對象提出最初的請求,客戶類只關心鏈的源頭,而無須關心請求的處理細節和傳遞過程。


模式實例

某系統提供一個假條審批的模塊,如果員工請假天數小於 3 天,主任可以審批該假條;如果員工請假天數大於等於 3 天,小於 10 天,經理可以審批;如果員工請假天數大於等於 10 天,小於 30 天,總經理可以審批;如果超過 30 天,總經理也不能審批,提示相應的拒絕信息。

在這裏插入圖片描述

  1. 請求類 LeaveRequest(請假條類)

    //	封裝請求的相關信息,以便處理者對其進行處理
    public class LeaveRequest {
    
        private String leaveName;
        private int leaveDays;
    
        public LeaveRequest(String leaveName, int leaveDays) {
            this.leaveName = leaveName;
            this.leaveDays = leaveDays;
        }
    
        public void setLeaveName(String leaveName) {
            this.leaveName = leaveName;
        }
    
        public void setLeaveDays(int leaveDays) {
            this.leaveDays = leaveDays;
        }
    
        public String getLeaveName() {
            return leaveName;
        }
    
        public int getLeaveDays() {
            return leaveDays;
        }
    }
    
  2. 抽象處理類 Leader(領導類)

    public abstract class Leader {
    
        protected String name;
        protected Leader successor;	//	作爲對下家的引用
    
        public Leader(String name) {
            this.name = name;
        }
    
        public void setSuccessor(Leader successor) {
            this.successor = successor;
        }
    
        public abstract void handleRequest(LeaveRequest request);
    }
    
  3. 具體處理者 Director(主任類)

    public class Director extends Leader {
    
        public Director(String name) {
            super(name);
        }
    
        @Override
        public void handleRequest(LeaveRequest request) {
            if (request.getLeaveDays() < 3) {
                System.out.println("主任" + name + "審批員工" + request.getLeaveName() +
                        "的請假條,請假天數爲" + request.getLeaveDays() + "天");
            } else {
                if (this.successor != null) {
                    this.successor.handleRequest(request);
                }
            }
        }
    }
    
  4. 具體處理者 Manager(經理類)

    public class Manager extends Leader {
    
        public Manager(String name) {
            super(name);
        }
    
        @Override
        public void handleRequest(LeaveRequest request) {
            if (request.getLeaveDays() < 10) {
                System.out.println("經理" + name + "審批員工" + request.getLeaveName() +
                        "的請假條,請假天數爲" + request.getLeaveDays() + "天");
            } else {
                if (this.successor != null) {
                    this.successor.handleRequest(request);
                }
            }
        }
    }
    
  5. 具體處理者 GeneralManager(總經理類)

    public class GeneralManager extends Leader {
    
        public GeneralManager(String name) {
            super(name);
        }
    
        @Override
        public void handleRequest(LeaveRequest request) {
            if (request.getLeaveDays() < 30) {
                System.out.println("總經理" + name + "審批員工" + request.getLeaveName() +
                        "的請假條,請假天數爲" + request.getLeaveDays() + "天");
            } else {
                System.out.println("想請假" + request.getLeaveDays() + "天?你是不想幹了吧!");
            }
        }
    }
    
  6. 客戶端測試類 Client

    public class Client {
    
        public static void main(String[] args) {
    
            Leader director = new Director("王明");
            Leader manager = new Manager("趙強");
            Leader generalManager = new GeneralManager("陳勇");
    
            director.setSuccessor(manager);
            manager.setSuccessor(generalManager);
    
            LeaveRequest lr1 = new LeaveRequest("張三", 2);
            director.handleRequest(lr1);
    
            LeaveRequest lr2 = new LeaveRequest("李四", 5);
            director.handleRequest(lr2);
    
            LeaveRequest lr3 = new LeaveRequest("王五", 15);
            director.handleRequest(lr3);
    
            LeaveRequest lr4 = new LeaveRequest("趙六", 45);
            director.handleRequest(lr4);
        }
    }
    
  7. 運行結果
    在這裏插入圖片描述


模式優缺點

職責鏈模式優點如下:

  1. 降低耦合度。對象不需知道是誰處理請求,之需等待處理結果即可。接收者和發送則都沒有對方的明確信息,且鏈中的對象不需要知道鏈的結構,由客戶端負責鏈的創建
  2. 簡化對象的相互連接。請求處理對象僅需維持一個指向其後繼者的引用,而不需維持對所有候選處理者的引用
  3. 增強給對象指派職責的靈活性。可以通過在運行時對該鏈進行動態的增加或修改來增加或改變一個請求
  4. 增加新的請求處理類很方便。增加一個新的具體請求處理者無須修改源代碼,只需在客戶端重新建鏈即可,符合開閉原則

職責鏈模式缺點如下:

  1. 不能保證請求一定被接收。該請求可能一直到末端都得不到處理,也有可能沒有被正確配置而得不到處理
  2. 對於較長的職責鏈,請求的處理可能涉及多個處理對象,系統性能將受到一定影響,進行代碼調式也不方便

模式適用環境

以下情況可以考慮使用職責鏈模式:

  1. 有多個對象可以處理同一請求,具體哪個對象處理由運行時刻決定
  2. 在不明確指定接收者的情況下,向多個對象中的一個提交請求。請求沿着鏈進行傳遞,尋找相應的處理者
  3. 動態指定一組對象處理請求,客戶端可以動態創建職責鏈來處理請求,還可以動態改變鏈中處理者之間的先後次序

純與不純的職責鏈模式

一個純的職責鏈模式要求某一處理者對象要麼接收請求,承擔責任,要麼把責任推給下家。在一個不純的職責鏈模式裏面,一個請求可以被由某一處理對象承擔一部分責任後,又將責任往下傳,或者最終不被任何接收端對象所接收。實際中我們接觸到的大多是不純的職責鏈模式。


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