標籤:

設計模式之責任鏈模式

題外話:本文的代碼我放在 Github 上,感興趣的可以去下載使用,在閱讀本文之前希望你熟悉 Java 語法基礎。

定義:責任鏈模式(Chain of Responsibility)使多個對象都有機會處理請求,從而避免請求的發送者和接受者之間的耦合關係。將這些對象連成一條鏈,並沿著這條鏈傳遞該請求,直到有對象能夠處理它。

類型:行為類模式

考慮以下這樣的場景:

你要去給某公司借款 1 萬元,當你來到櫃檯的時候向櫃員發起 "借款 1 萬元" 的請求時,櫃員認為金額太多,處理不了這樣的請求,他轉交這個請求給他的組長,組長也處理不了這樣的請求,那麼他接著向經理轉交這樣的請求。

用 Java 代碼表示為:

public void test(Request request) {n int money = request.getRequestMoney();n if(money <= 1000) {n Clerk.response(request);tn } else if(money <= 5000) {n Leader.response(request);n } else if(money <= 10000) {n Manager.response(request);n }n}n

代碼的業務邏輯就是這樣:根據的借款金額來判定誰來處理這個借款請求 (request)

  • 如果請求借款金額小於 1000 元,那麼櫃檯職員就可以直接處理這個請求(比如簽字)
  • 如果請求借款金額小於 5000 元但大於 1000 元,那麼職員處理不了,該請求轉交給組長,組長能夠處理這樣的請求(比如簽字)
  • 如果請求借款金額大於 5000 元但小於 10000 元,那麼職員和組長都處理不了(沒有許可權),那麼這個請求就會轉交給經理,經理能夠處理這樣的請求(比如簽字)

在編程中,這樣處理業務邏輯的方法非常常見,這樣的方法非常直觀,簡單明了,並且也比較容易維護,但是同時它也存在著著問題:

  1. 代碼臃腫: 實際應用中的判定條件通常不是這麼簡單地判斷金額,也許需要複雜的操作,也許需要查詢資料庫等等,這就會產生許多額外的代碼,如果判斷條件再比較多的話,那麼代碼就會大量地堆積在同一個文件中。
  2. 耦合度高:如果我們想繼續添加處理請求的類,那麼就需要添加 else if 的判定條件;另外,這個條件判定的順序也是寫死的。如果想改變順序,那麼也只能修改這個條件語句。

下面就介紹責任鏈模式:

責任鏈模式的類圖非常簡單,如下圖:

1. 抽象處理類: 主要包含一個指向下一處理類的成員變數 nextHandler 和一個處理請求的方法 handRequest,handRequest 方法的主要思想是,如果滿足處理的條件,則有本處理類來進行處理,否則由 nextHandler 來處理。

2. 具體處理類:具體處理類的主要是對具體的處理邏輯和處理的適用條件進行實現。

了解完責任鏈的大體思想之後,在看看 Java 代碼是如何實現的:

等級類:

public class Level {n private int level = 0;n public Level(int level) {n this.level = level;n }n public int getLevel() {n return level;n }n public boolean above(Level level) {n if(this.level >= level.getLevel()) {n return true;n }else {n return false;n }n }n}n

請求與響應:

//請求nclass Request {n Level level;n public Request(Level level) {n System.out.println("開始請求...");n this.level = level;n }n public Level getLevel() {n return level;n }n}nn//響應nclass Response {n private String message;n public Response(String message) {n System.out.println("處理完請求");n this.message = message;n }n public String getMessage() {n return message;n }n}n

代碼中 Request、Response 分別代表請求和響應,Level 類代表等級,above 方法用於比較等級,等級低的無法處理等級高的請求,所以返回 false,等級高的可以處理等級相同或者低的請求,返回 true。

抽象處理類和具體處理類:

//抽象處理器nabstract class Handler {n private Handler nextHandler = null;n public void setNextHandler(Handler handler) {n nextHandler = handler;n }n public final Response handlerRequest(Request request) {n Response response = null;n if(this.getHandlerLevel().above(request.getLevel())) {n response = this.response(request);n }else {n if(nextHandler != null) {n response = this.nextHandler.handlerRequest(request);n }else {n System.out.println("沒有合適的處理器處理該請求...");n }n }n return response;n }n protected abstract Level getHandlerLevel();n public abstract Response response(Request request); n}nn//具體的處理器 1nclass ConcreteHandler1 extends Handler {n protected Level getHandlerLevel() {n return new Level(1);n }n public Response response(Request request) {n System.out.println("該請求由 ConcreteHandler1 處理");n return new Response("響應結果 1");n }n}nn//具體的處理器 2nclass ConcreteHandler2 extends Handler {n protected Level getHandlerLevel() {n return new Level(2);n }n public Response response(Request request) {n System.out.println("該請求由 ConcreteHandler2 處理");n return new Response("響應結果 2");n }n}nn//具體的處理器 3nclass ConcreteHandler3 extends Handler {n protected Level getHandlerLevel() {n return new Level(3);n }n public Response response(Request request) {n System.out.println("該請求由 ConcreteHandler3 處理");n return new Response("響應結果 3");n }n}n

抽象類 Handler 中主要進行條件的判斷,只有處理類的處理等級高於 Request 的等級才能處理,否則交給下一個處理者處理。

客戶端調用:

public class Client {n public static void main(String[] args) {n Handler ch1 = new ConcreteHandler1();n Handler ch2 = new ConcreteHandler2();n Handler ch3 = new ConcreteHandler3();nn ch1.setNextHandler(ch2);n ch2.setNextHandler(ch3);nn Response res1 = ch1.handlerRequest(new Request(new Level(2)));n if (res1 != null) {n System.out.println(res1.getMessage());nt}n Response res2 = ch1.handlerRequest(new Request(new Level(4)));n if (res2 != null) {n System.out.println(res2.getMessage());n }n } n}n

在 Client 類中處理好鏈的前後執行順序,執行時將請求交給第一個處理類,也就是等級最低的處理類,這就是責任鏈模式,它完成的功能與前文 if...else... 方法相同。

運行結果:

總結:

  1. 責任鏈模式與 if...else 相比,他的耦合性要低一些,因為它將條件判定分散到各個處理類中,並且這些處理類的優先處理順序可以隨意的設定,並且如果想要添加新的 handler 類也是十分簡單的,這符合開放閉合原則。
  2. 責任鏈模式帶來了靈活性,但是在設置處理類前後關係時,一定要避免在鏈中出現循環引用的問題。

最後我們使用責任鏈模式來完成一個實際的場景:

有一個銀行的借款系統可以幫助用戶借款,負責該系統的有職員,組長還有經理,他們的等級由低到高,並且他們能夠允許借款的額度也是從低到高的,分別是:

  1. 職員最高可以批准 5000 元的借款額度
  2. 組長最高可以批准 20000 元的借款額度
  3. 經理最高可以批准 100000 元的借款額度

當有轉賬的請求過來時,先由等級低的員工處理,若無法處理,則將請求移交給上級處理。

根據上面的場景,運用責任鏈模式,用 Java 代碼表示為:

首先先定義借款請求:

class BorrowRequest {n private int requestMoney;n public BorrowRequest(int money) {n System.out.println("有新請求,需要借款 " + money + " 元");n requestMoney = money;n }n public int getMoney() {n return requestMoney;n }n}n

然後再定義一個抽象職員類,用於實現責任鏈:

abstract class AbstractClerk {n private AbstractClerk superior = null;n protected String type;n public void setSuperior(AbstractClerk superior) {n this.superior = superior;n } n public void approveRequest(BorrowRequest request) {n if(getLimit() >= request.getMoney()) {n System.out.println(getType() + "同意借款請求");n }else {n if(this.superior != null) {n this.superior.approveRequest(request);n }else {n System.out.println("沒有人能夠同意借款請求");n }n }n }n public abstract int getLimit();n public String getType() {n return type;n }n}n

實現完抽象職員類之後,只需要創建具體的員工類,並設置其額度就可以了。

class Clerk extends AbstractClerk{n public Clerk() {n super.type = "職員";n }n public int getLimit() {n return 5000;n }n}nnclass Leader extends AbstractClerk{n public Leader() {n super.type = "組長";n }n public int getLimit() {n return 20000;n }n}nnclass Manager extends AbstractClerk{n public Manager() {n super.type = "經理";n }n public int getLimit() {n return 100000;n }n}n

最後在客戶端調用:

public class Client {n public static void main(String[] args) {n AbstractClerk clerk = new Clerk();n AbstractClerk leader = new Leader();n AbstractClerk manager = new Manager();nn clerk.setSuperior(leader);n leader.setSuperior(manager);nn //有人借款 10000 元n clerk.approveRequest(new BorrowRequest(10000));nn //有人借款 111000 元n clerk.approveRequest(new BorrowRequest(111000));nn }n}n

運行結果:

這時候如果添加了新的職位老版,他的額度為 1000000 元,那麼我們只需創建一個新的具體職員類繼承抽象職工類即可。

class Boss extends AbstractClerk{n public Boss() {n super.type = "老版";n }n public int getLimit() {n return 1000000;n }n}nnpublic class Client {n public static void main(String[] args) {n AbstractClerk clerk = new Clerk();n AbstractClerk leader = new Leader();n AbstractClerk manager = new Manager();n AbstractClerk boss = new Boss();nn clerk.setSuperior(leader);n leader.setSuperior(manager);n manager.setSuperior(boss);nn //有人借款 10000 元n clerk.approveRequest(new BorrowRequest(10000));nn //有人借款 111000 元n clerk.approveRequest(new BorrowRequest(111000));nn }n}n

運行結果:


推薦閱讀:

設計模式之職責鏈模式
設計模式之策略模式
Lua的好處是什麼以及如何用Lua設計所謂「組件式架構」?
設計模式之七大基本原則
設計模式之單例模式

TAG:设计模式 |