Java設計模式——職責鏈模式:解鎖高效靈活的請求處理之道

嘿,各位 Java 編程大神和愛好者們!今天咱們要一同深入探索一種超厲害的設計模式——職責鏈模式。它就像一條神奇的“處理鏈”,能讓請求在多個對象之間有條不紊地傳遞,直到找到最合適的“處理者”。準備好跟我一起揭開它神秘的面紗,看看如何用代碼實現(xiàn)這種強大的模式,讓我們的程序變得更加智能和靈活吧!??

一、職責鏈模式:請求處理的“智能傳送帶”??

(一)模式定義與神奇特點

職責鏈模式可是對象行為模式家族里的“明星成員”哦!想象一下,有一群對象像鏈條上的環(huán)一樣緊密相連,每個對象都知道下一個對象是誰(持有下家的引用)。當一個請求像小包裹一樣在這條鏈上傳遞時,它會逐個經(jīng)過這些對象。而發(fā)出請求的客戶端呢,就像把包裹送到快遞公司后就安心等待結(jié)果一樣,完全不用操心到底是哪個對象最終會處理這個請求。這種模式最大的魅力在于它賦予了系統(tǒng)超級強大的靈活性。比如說,我們可以隨時調(diào)整這條鏈的結(jié)構(gòu),添加、刪除或者重新排列處理者,而客戶端那邊卻感覺不到任何變化,就像魔法一樣!??♂?

用一個超形象的比喻來理解,職責鏈模式就像是一場接力賽跑,每個選手(處理者)都有自己的能力范圍(處理條件)。當接力棒(請求)傳來時,如果這個選手有能力完成接下來的路程(處理請求),那就全力沖刺;如果覺得自己力不從心,就迅速把接力棒交給下一個選手,直到找到那個能沖過終點線(處理請求)的“大神”選手。

再舉個生活中的例子,就拿擊鼓傳花來說吧。一群小伙伴圍成一個圈(形成責任鏈),鼓聲響起時開始傳花(請求傳遞)。每個小伙伴就像是鏈上的一個處理者,當花傳到自己手上時,如果鼓聲停止(滿足某種條件),那這個小伙伴就要表演節(jié)目(處理請求);如果鼓聲還在響,就趕緊把花傳給下一個小伙伴。這里的小伙伴們可以站成直線、圍成環(huán)形或者組成樹狀結(jié)構(gòu)的一部分,具體怎么站完全取決于大家想怎么玩這個游戲(業(yè)務邏輯和需求)。??
<separator></separator>

(二)模式結(jié)構(gòu)大揭秘

  1. 抽象處理者(Handler):鏈的“基石”與“規(guī)則制定者”
    • 抽象處理者就像是整個職責鏈的“總設計師”,它定義了處理請求的統(tǒng)一接口,就像給所有處理者制定了一套必須遵守的“游戲規(guī)則”。在某些情況下,它還會規(guī)定怎么設置和獲取下一個處理者(下家)的方法。一般來說,它會以抽象類或者接口的形式存在,為具體的處理者提供了一個清晰的行為框架和接口規(guī)范,確保所有處理者都能“按章辦事”。就好比建筑藍圖,規(guī)定了房子該怎么蓋,每個房間的布局和功能一樣。??
  2. 具體處理者(ConcreteHandler):請求的“接收者”與“傳遞者”
    • 具體處理者可是鏈上的“實干家”,當請求送到它面前時,它有兩種選擇。一種是根據(jù)自己的能力和判斷,決定是否親自處理這個請求。如果它覺得自己能行,就會按照自己的方式處理請求,就像廚師根據(jù)訂單(請求)烹飪美食(處理邏輯);另一種情況是,如果它覺得自己搞不定,或者根據(jù)業(yè)務規(guī)則應該讓更厲害的人來處理,它就會毫不猶豫地把請求轉(zhuǎn)交給下家。因為它知道下家是誰(持有下家引用),所以能輕松地把請求傳遞下去,讓請求繼續(xù)在鏈上“旅行”。就像快遞員,如果發(fā)現(xiàn)包裹的目的地不在自己的配送范圍內(nèi),就會轉(zhuǎn)交給下一個區(qū)域的快遞員。??

(三)代碼實現(xiàn):構(gòu)建職責鏈

下面是一個用 Java 實現(xiàn)的職責鏈模式的簡單示例代碼,讓我們一起來看看它是如何工作的。

// 抽象處理者(Handler)
abstract class Handler {
    // 持有下一個處理者的引用
    protected Handler successor;

    // 設置下一個處理者的方法
    public void setSuccessor(Handler successor) {
        this.successor = successor;
    }

    // 抽象的處理請求方法,具體處理邏輯由子類實現(xiàn)
    abstract public void handleRequest(int request);
}

// 具體處理者 1(ConcreteHandler1)
class ConcreteHandler1 extends Handler {
    @Override
    public void handleRequest(int request) {
        // 如果請求在 0 到 10 之間(這里只是一個簡單的示例條件),則由當前處理者處理
        if (request >= 0 && request < 10) {
            System.out.println(this + " handled request " + request);
        } else if (successor!= null) {
            // 否則,將請求傳遞給下一個處理者(如果有下家的話)
            successor.handleRequest(request);
        }
    }
}

// 具體處理者 2(ConcreteHandler2)
class ConcreteHandler2 extends Handler {
    @Override
    public void handleRequest(int request) {
        if (request >= 10 && request < 20) {
            System.out.println(this + " handled request " + request);
        } else if (successor!= null) {
            successor.handleRequest(request);
        }
    }
}

// 具體處理者 3(ConcreteHandler3)
class ConcreteHandler3 extends Handler {
    @Override
    public void handleRequest(int request) {
        if (request >= 20 && request < 30) {
            System.out.println(this + " handled request " + request);
        } else if (successor!= null) {
            successor.handleRequest(request);
        }
    }
}

// 客戶端測試類
public class Client {
    public static void main(String[] args) {
        // 創(chuàng)建處理者對象
        Handler h1 = new ConcreteHandler1();
        Handler h2 = new ConcreteHandler2();
        Handler h3 = new ConcreteHandler3();

        // 設置處理者之間的鏈關系,形成 h1 -> h2 -> h3 的鏈
        h1.setSuccessor(h2);
        h2.setSuccessor(h3);

        // 生成一些請求并處理
        int[] requests = {2, 5, 14, 22, 18, 3, 27, 20};

        for (int request : requests) {
            h1.handleRequest(request);
        }
    }
}
Responsibility.jpg

(四)純與不純的職責鏈模式

  1. 純職責鏈模式:規(guī)則嚴格的“處理鏈”
    • 在純職責鏈模式的世界里,規(guī)則那是相當嚴格的。對于每一個具體的處理者來說,當收到請求時,它只能二選一:要么勇敢地承擔起處理請求的全部責任,就像獨自扛起一座大山;要么毫不猶豫地把責任推給下家,絕不拖泥帶水。而且,在這條鏈上,每個請求就像一個被精心安排的小旅客,必定會被某個處理者收留并妥善處理,絕對不會出現(xiàn)被忽視、流落街頭的情況。不過呢,這種模式在現(xiàn)實生活中的例子比較少,因為它的實現(xiàn)和應用場景相對來說有點“挑食”,要求比較高,不夠靈活。就像一個只接受特定規(guī)格零件的精密儀器,稍微有點不匹配就無法工作。??
  2. 不純職責鏈模式:適應變化的“萬能鏈”
    • 不純職責鏈模式就隨和多了,它允許請求在傳遞過程中,即使經(jīng)過了所有的處理者,也可能找不到一個愿意收留它的“家”。這種模式在實際開發(fā)中可是非常受歡迎的“大眾明星”,因為它能更好地應對復雜多變的業(yè)務需求。比如說,在某些業(yè)務場景中,一個請求可能像一個挑剔的顧客,在經(jīng)過一系列的服務者(處理者)后,還是沒有找到滿意的服務(沒有合適的處理者)。這時候,系統(tǒng)可以根據(jù)預先設定的策略,比如記錄下這個“挑剔顧客”的需求(記錄日志),或者禮貌地告訴它“不好意思,我們無法滿足您的需求”(返回錯誤信息)。就像一家餐廳,如果遇到顧客點了菜單上沒有的菜品,服務員可以記錄下來反饋給廚房(記錄日志),或者向顧客解釋并推薦其他菜品(返回錯誤信息)。??

(五)實際應用案例:采購審批系統(tǒng)中的職責鏈

讓我們來看一個更貼近實際工作場景的例子——采購審批系統(tǒng)。

// 抽象審批者(Approver)
abstract class Approver {
    // 審批者姓名
    protected String name;
    // 持有下一個審批者的引用
    protected Approver successor;

    // 構(gòu)造函數(shù),初始化審批者姓名
    public Approver(String name) {
        this.name = name;
    }

    // 設置下一個審批者的方法
    public void setSuccessor(Approver successor) {
        this.successor = successor;
    }

    // 抽象的審批請求方法,具體審批邏輯由子類實現(xiàn)
    abstract public void processRequest(PurchaseRequest request);
}

// 主管審批者(Director)
class Director extends Approver {
    public Director(String name) {
        super(name);
    }

    @Override
    public void processRequest(PurchaseRequest request) {
        if (request.getAmount() < 10000.0) {
            System.out.println(this + " " + name + " approved request# " + request.getNumber());
        } else if (successor!= null) {
            successor.processRequest(request);
        }
    }
}

// 副總裁審批者(VicePresident)
class VicePresident extends Approver {
    public VicePresident(String name) {
        super(name);
    }

    @Override
    public void processRequest(PurchaseRequest request) {
        if (request.getAmount() < 25000.0) {
            System.out.println(this + " " + name + " approved request# " + request.getNumber());
        } else if (successor!= null) {
            successor.processRequest(request);
        }
    }
}

// 總裁審批者(President)
class President extends Approver {
    public President(String name) {
        super(name);
    }

    @Override
    public void processRequest(PurchaseRequest request) {
        if (request.getAmount() < 100000.0) {
            System.out.println(this + " " + name + " approved request# " + request.getNumber());
        } else {
            System.out.println("Request# " + request.getNumber() + " requires an executive meeting!");
        }
    }
}

// 采購請求類(PurchaseRequest)
class PurchaseRequest {
    private double amount;
    private int number;

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

    public double getAmount() {
        return amount;
    }

    public int getNumber() {
        return number;
    }
}

在這個采購審批系統(tǒng)中,我們定義了不同級別的審批者,從主管、副總裁到總裁,他們就像一條職責鏈上的各個環(huán)節(jié)。當一個采購請求(就像一個任務包裹)被提交后,它會從主管開始,沿著這條審批鏈依次傳遞。如果采購金額比較小,比如小于 10000 元,主管就可以直接批準(處理請求);如果金額超過了主管的審批權(quán)限,主管就會把請求交給副總裁。副總裁也會根據(jù)金額大小決定是否批準,如果金額超過了副總裁的權(quán)限,就繼續(xù)傳遞給總裁。這樣,不同金額的采購請求就能找到合適的審批者進行處理。而且,如果未來公司的審批流程發(fā)生了變化,比如增加了新的審批層級或者修改了審批金額的限制,我們只需要在相應的審批者類中進行修改,就像調(diào)整鏈條上的某個環(huán)節(jié)一樣,不會對整個審批系統(tǒng)的結(jié)構(gòu)造成太大的影響。這就是職責鏈模式在實際應用中的強大之處,它讓系統(tǒng)變得更加靈活和易于維護。??

二、總結(jié)與展望:職責鏈模式的無限潛力??

通過對職責鏈模式的深入學習,我們就像獲得了一把神奇的鑰匙,可以打開高效靈活處理請求的大門。它不僅讓我們的代碼結(jié)構(gòu)更加清晰,各個處理者之間的職責分明,還讓系統(tǒng)能夠輕松應對各種變化,無論是業(yè)務規(guī)則的調(diào)整還是處理流程的優(yōu)化。

在未來的開發(fā)中,我們可以繼續(xù)探索職責鏈模式的更多應用場景,比如在工作流系統(tǒng)、消息處理系統(tǒng)、異常處理機制等方面都可以發(fā)揮它的優(yōu)勢。同時,我們也可以結(jié)合其他設計模式,如工廠模式來創(chuàng)建處理者對象,或者結(jié)合裝飾者模式來增強處理者的功能,讓我們的程序更加健壯和強大。相信只要我們善于運用這些設計模式,就能打造出更加優(yōu)秀、高效的軟件系統(tǒng),在編程的世界里創(chuàng)造更多的精彩!??

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容