在日常生活中,我們如果仔細觀察的話,很多事情都蘊含著責任鏈模式的思想;比如某個人去售樓處買房,對銷售人員提出打折的要求,如果折扣比較
小,銷售人員有權給予該購買者提出的折扣優惠,就可以直接答應該請求;如果折扣過大,銷售人員無權答應,則會想他的上司——銷售組長詢問,
如果銷售組長有權答應該折扣,則直接回復可以,並將房子售賣給客戶;以此類推,直至該折扣請求被處理,客戶得到相應的答覆,該事件結束。
再比如,我們曾經玩過的拋手絹、擊鼓傳花等遊戲,都有責任鏈模式的影子;總的來說,責任鏈模式就是:將接收者物件連城一條鏈,將對應的請求
在該鏈上進行傳遞,直至有接收者物件處理了該請求;這種通過允許更多接收者物件有機會對請求進行處理,來避免請求者和接收者之間的耦合;
其中,責任鏈模式中的“責任鏈”源於在鏈上的每個處理者都有責任去處理在鏈上傳遞的請求,同時,處理者對應不同等級的請求,相應地有處理請求
的許可權;
另外,在上面的例子中,購房者不需要知道誰處理了他的折扣請求,擊鼓傳花中,擊鼓者,也不需要知道是誰拿到花並進行節目表演,這就解釋了
上面說的請求者和接收處理者之間的去耦合是怎麼一回事。
下面將以生活中公司中職員請假的流程作為示例,採用責任鏈模式進行程式碼的設計,通過直觀的講解來闡述責任鏈模式的設計思想;
package com.pattern.handler;
/**
* 假期申請接收者對應的抽象類,負責處理工作人員的假期申請
*/
public abstract class LeaveHandler
{
/**
* 直接後繼管理人員,用於傳遞請求
*/
protected LeaveHandler successor;
public void setSuccessor(LeaveHandler successor)
{
this.successor = successor;
}
/**
* 處理假期申請
*/
public abstract void processLeave(int days);
}
package com.pattern.handler;
/**
* 組長類, 可以批准2天以內的假期申請
*/
public class GroupLeader extends LeaveHandler
{
@Override
public void processLeave(int days)
{
if(days<=2)
{
System.out.println(this.getClass().getName()+"批准了"+days+"天假");
}
else
{
successor.processLeave(days);
}
}
}
package com.pattern.handler;
/**
* 副主任類, 可以批准3天以內的假期申請
*/
public class ViceManager extends LeaveHandler
{
@Override
public void processLeave(int days)
{
if(days<=3)
{
System.out.println(this.getClass().getName()+"批准了"+days+"天假");
}
else
{
successor.processLeave(days);
}
}
}
package com.pattern.handler;
/**
* 主任類, 可以批准5天以內的假期申請
*/
public class Manager extends LeaveHandler {
@Override
public void processLeave(int days)
{
if(days<=5)
{
System.out.println(this.getClass().getName()+"批准了"+days+"天假");
}
else
{
successor.processLeave(days);
}
}
}
package com.pattern.handler;
/**
* 總經理類,可以批准10天以內的假期申請
* 假期超過10天, 就拒絕申請
*/
public class GeneralManager extends LeaveHandler {
@Override
public void processLeave(int days)
{
if(days<=10)
{
System.out.println(this.getClass().getName()+"批准了"+days+"天假");
}
else
{
System.out.println(this.getClass().getName()+"不批准"+days+"天假");
}
}
}
package com.pattern.handler;
public class LeaveHandlerFactory {
/**
* 建立LeaveHandler的工廠方法
*/
public static LeaveHandler createPriceHandler()
{
LeaveHandler gl = new GroupLeader();
LeaveHandler vm = new ViceManager();
LeaveHandler m = new Manager();
LeaveHandler gm = new GeneralManager();
gl.setSuccessor(vm);
vm.setSuccessor(m);
m.setSuccessor(gm);
return gl;
}
}
package com.pattern;
import java.util.Random;
import com.pattern.handler.LeaveHandler;
import com.pattern.handler.LeaveHandlerFactory;
/**
* 工作人員,申請假期
*/
public class Client {
private LeaveHandler leaveHandler;
public void setLeaveHandler(LeaveHandler leaveHandler)
{
this.LeaveHandler = leaveHandler;
}
public void requestLeave(int days)
{
leaveHandler.processLeave(days);
}
public static void main(String[] args)
{
Client client = new Client();
client.setLeaveHandler(LeaveHandlerFactory.
createLeaveHandler());
Random random = new Random();
for(int i=1;i<=100;i++){
System.out.print(i+":");
client.requestLeave(random.nextInt(20));
}
}
}
程式碼重點分析:
①抽象類LeaveHandler包含一個自身型別的資料域,這個資料域的別名叫做責任鏈上的後繼者,當本類的物件無權處理請求時,就將該請求傳遞
給該資料域對應的物件進行處理,這一點非常重要,是形成責任鏈的關鍵所在!
②抽象類LeaveHandler屬於Java中泛指的介面,這裡使用抽象類作為介面,體現了面向介面程式設計的思想,這一點要注意!
③這裡將不同型別的處理者的產生交由工廠類LeaveHandlerFactory來完成,體現了物件導向(OO)中類設計的單一職責原則,即對於某一
介面或類,只把該介面或類的相關方法放進該介面或類中。同時,Java的命名規範要求我們設計類或介面時,能夠見名知意,每一個類的類名必須
代表著該類的語義!
④通過分析上述程式碼,可以發現職員類只和import com.pattern.handler.LeaveHandler以及import com.pattern.handler.LeaveHandlerFactory兩個類相關聯,
並沒有和繼承於抽象類LeaveHandler的具體類相關聯,這就帶來了業務變更時,
無需修改介面,只需要增加繼承於LeaveHandler的類即可;比如,當公司中等級變化時(對應管理人員的等級有所增加),可以通過再設計一個
對應類,並在工廠類中進行該類物件的獲取,並將其嵌入責任鏈中,即可實現該專案仍可以正常工作,這就體現了設計模式應對不同場景時獨具
的優勢,體現了專案的可擴充套件性!
在責任鏈模式中存在著一些缺點,就本例來說:
①當請假的天數較少,只需要經過一個或者少數的處理者就可以處理該請求,那麼這就造成之後的處理者被建立出來,但是並沒有參與業務
處理,造成時間和空間上的浪費。
②當多個職員請假時,需要分別建立一組管理人員物件,這就造成了不必要的開銷,其實,只需一組管理人員物件即可處理多名職員的請假請求。
責任鏈模式在Java的前端或者後臺開發中也會常常遇到,比如後端開發中遇到的異常處理機制、Java Web中的過濾器鏈;
前端開發中的JavaScript中的事件觸發處理過程,都蘊含了責任鏈模式的設計思想!