故名思義責(zé)任鏈模式中存在一個(gè)鏈?zhǔn)浇Y(jié)構(gòu),鏈?zhǔn)浇Y(jié)構(gòu):多外節(jié)點(diǎn)首尾相連标捺,每個(gè)節(jié)點(diǎn)都可以被拆分再連接剿另。具體什么是責(zé)任鏈模式呢媚值。它使多個(gè)對(duì)象都有機(jī)會(huì)處理請(qǐng)求驶鹉,從而避免請(qǐng)求的發(fā)送者和接受者之間的耦合關(guān)系脚囊,將這個(gè)對(duì)象連成一條鏈挨约,并沿著這個(gè)條鏈傳遞該請(qǐng)求噩凹,直到有一個(gè)對(duì)象處理它為止曹锨。將每一個(gè)節(jié)點(diǎn)看作是一個(gè)對(duì)象临扮,每一個(gè)對(duì)象擁有不同的處理邏輯论矾,將一個(gè)請(qǐng)求從鏈?zhǔn)降氖锥伟l(fā)出,沿著鏈的路徑傳遞給每一個(gè)節(jié)點(diǎn)對(duì)象公条,直到有對(duì)象處理這個(gè)請(qǐng)求為止拇囊。
責(zé)任鏈模式看起來(lái)可能比較陌生,可是我們?cè)谌粘i_(kāi)發(fā)卻經(jīng)常碰到這種形式靶橱。
public void handleSomething(int eventNum){
switch (eventNum){
case 1:
//do something
break;
case 2:
//do something
break;
case 3:
//do something
break;
default:
//do something
}
}
switch或者if-else這種就是責(zé)任鏈的裸體樣式寥袭,是最簡(jiǎn)單的實(shí)現(xiàn)格式。當(dāng)然這是個(gè)不恰當(dāng)?shù)睦庸匕裕琲f-else嵌套太多传黄,很可能你都看不懂你的代碼。
舉個(gè)粟子
下面給一個(gè)簡(jiǎn)單的例子:
這個(gè)例子很簡(jiǎn)單队寇,一個(gè)抽象的Handler(處理者角色)和一個(gè)繼承Handler的具體實(shí)現(xiàn)者ConcreteHandler膘掰。
類圖
代碼
Handler類:
public abstract class Handler {
/**
* 持有下一個(gè)處理節(jié)點(diǎn)
*/
protected Handler successor;
/**
* 這個(gè)方法是具體的請(qǐng)求處理方法,在這里為了簡(jiǎn)化而沒(méi)有傳入?yún)?shù)
*/
public abstract void handleRequest();
/**
* 取出下一個(gè)節(jié)點(diǎn)的方法
*/
public Handler getSuccessor() {
return successor;
}
/**
* 賦值下一個(gè)節(jié)點(diǎn)的方法
*/
public void setSuccessor(Handler successor) {
this.successor = successor;
}
}
ConcreteHandler 類:
public class ConcreteHandler extends Handler {
@Override
public void handleRequest() {
/**
* 判斷是否有下個(gè)節(jié)點(diǎn)的責(zé)任處理對(duì)象
* 如果有,就轉(zhuǎn)發(fā)請(qǐng)求給下一個(gè)責(zé)任處理對(duì)象
* 如果沒(méi)有识埋,則處理請(qǐng)求
*/
if (getSuccessor() != null) {
System.out.println("放過(guò)請(qǐng)求");
getSuccessor().handleRequest();
} else {
System.out.println("處理請(qǐng)求");
}
}
}
Cilent類:
public class Client {
public static void main(String[] args) {
Handler handler1 = new ConcreteHandler();
Handler handler2 = new ConcreteHandler();
handler1.setSuccessor(handler2);
handler1.handleRequest();
}
}
Android/java 中應(yīng)用責(zé)任鏈模式的場(chǎng)景
- 在android比較明顯的就是事件分發(fā)過(guò)程中對(duì)事件的投遞凡伊。嚴(yán)格說(shuō)來(lái),事件投遞并不是嚴(yán)格的責(zé)任鏈模式窒舟,是責(zé)任鏈模式的變種實(shí)現(xiàn)系忙。子 View 的 onTouchEvent 返回 true 代碼消費(fèi)該事件并不再傳遞,false 代表不消費(fèi)并且傳遞到父 ViewGroup 去處理惠豺,這些樹(shù)形結(jié)構(gòu)的子 View 就是責(zé)任鏈上一個(gè)個(gè)處理對(duì)象银还;
- OrderedBroadcast,廣播的每一個(gè)接收者按照優(yōu)先級(jí)依次接受消息洁墙,如果處理完成之后可以調(diào)用 abortBroadcast 終止廣播蛹疯,不是自己處理的就可以傳遞給下一個(gè)處理者;
- try-catch語(yǔ)句热监,每一個(gè) catch 根據(jù) Exception 類型進(jìn)行匹配捺弦,形成一個(gè)責(zé)任鏈,如果有一個(gè) catch 語(yǔ)句與該 Exception 符合孝扛,這個(gè) Exception 就交由給它進(jìn)行處理羹呵,之后所有 catch 語(yǔ)句都不會(huì)再次執(zhí)行。
再來(lái)看看具體的粟子
如果一個(gè)程序員一個(gè)月連續(xù)加班疗琉,這個(gè)月算下來(lái)可以調(diào)休5天。然后這個(gè)coder寫(xiě)了調(diào)休申請(qǐng)給項(xiàng)目經(jīng)理歉铝,可項(xiàng)目經(jīng)理有點(diǎn)方了盈简,他只能審批調(diào)休一天的,然后項(xiàng)目經(jīng)理把你的申請(qǐng)交給部門(mén)經(jīng)理太示,部門(mén)經(jīng)理一看也沒(méi)法柠贤,公司規(guī)則多,他只能審批多超過(guò)三天的类缤,只能讓總經(jīng)理過(guò)目了臼勉。
那看看具體代碼。
//這個(gè)是leader的抽象類
public abstract class Leader {
private Leader successor;
private int hoildayNum;
private String position;
public void setPosition(String position) {
this.position = position;
}
public String getPosition() {
return position;
}
public Leader(int hoildayNum) {
this.hoildayNum = hoildayNum;
}
public abstract void reply(Worker worker);
public void handleRequest(Worker worker) {
if (worker.getHolidayNum() <= hoildayNum) {
reply(worker);
} else {
if (null != successor) {
successor.handleRequest(worker);
} else {
System.out.println(position + "拒絕了你的請(qǐng)求");
}
}
}
public void setSuccessor(Leader successor) {
this.successor = successor;
}
}
/**
* 項(xiàng)目經(jīng)理處理類
*/
public class ProjectDirector extends Leader {
public ProjectDirector(int hoildayNum) {
super(hoildayNum);
setPosition("項(xiàng)目經(jīng)理");
}
@Override
public void reply(Worker worker) {
System.out.println(getPosition() + "已通過(guò)你的請(qǐng)求");
}
}
/**
* 部門(mén)經(jīng)理處理類
*/
public class DepartmentManager extends Leader {
public DepartmentManager(int hoildayNum) {
super(hoildayNum);
setPosition("部門(mén)經(jīng)理");
}
@Override
public void reply(Worker worker) {
System.out.println(getPosition() + "已通過(guò)你的請(qǐng)求");
}}
/**
* 總經(jīng)理處理類
*/
public class GeneralManager extends Leader {
public GeneralManager(int hoildayNum) {
super(hoildayNum);
setPosition("總經(jīng)理");
}
@Override
public void reply(Worker worker) {
System.out.println(getPosition() + "已通過(guò)請(qǐng)求");
}
}
public class Cilent {
public static void main(String[] args) {
Worker worker = new Worker(6);
Leader projectDir = new ProjectDirector(1);
Leader departmentMan = new DepartmentManager(3);
Leader generalMan = new GeneralManager(10);
projectDir.setSuccessor(departmentMan);
departmentMan.setSuccessor(generalMan);
projectDir.handleRequest(worker);
}
}
這樣我們就把請(qǐng)求者與處理者優(yōu)雅的解耦餐弱。
純與不純的責(zé)任鏈模式
很多資料中會(huì)介紹純和不純的責(zé)任鏈模式宴霸,在標(biāo)準(zhǔn)的責(zé)任鏈模式中,責(zé)任鏈上的一個(gè)節(jié)點(diǎn)只允許有兩個(gè)行為:處理或者推給下個(gè)節(jié)點(diǎn)處理膏蚓,而不允許處理完之后又推給下個(gè)節(jié)點(diǎn)瓢谢,前者被很多資料稱為純的責(zé)任鏈模式,而后者被稱為不純的責(zé)任鏈模式驮瞧。其實(shí)在實(shí)際的系統(tǒng)里氓扛,純的責(zé)任鏈很難找到。如果堅(jiān)持責(zé)任鏈不純便不是責(zé)任鏈模式论笔,那么責(zé)任鏈模式便不會(huì)有太大意義了采郎。