下面距芬,將通過一個(gè)例子,對(duì)職責(zé)鏈模式進(jìn)行介紹循帐。
問題:設(shè)想框仔,你有一個(gè)呼叫中心,員工分成三個(gè)層級(jí)拄养,接線員离斩,主管和經(jīng)理”衲洌客戶來(lái)電時(shí)會(huì)先分配給接線員跛梗,若接線員處理不了,就必須將來(lái)電往上轉(zhuǎn)給主管棋弥,若主管無(wú)法處理核偿,將來(lái)電往上轉(zhuǎn)給經(jīng)理。請(qǐng)?jiān)O(shè)計(jì)這個(gè)問題的類和數(shù)據(jù)結(jié)構(gòu)(為了方便顽染,將呼叫者的問題分等級(jí)漾岳,分別為 S 級(jí)轰绵,由接線員處理,SS 級(jí)尼荆,由主管處理左腔,SSS級(jí),由經(jīng)理處理)耀找。
首先翔悠,分析一下這個(gè)問題业崖,對(duì)于一次電話呼叫野芒,肯定存在 呼叫人和被呼叫人,所以我們可能需要設(shè)計(jì)一個(gè) Call 類來(lái)表示一個(gè)電話呼叫双炕,一個(gè) Caller 類用于封裝呼叫人的屬性狞悲,Employee 類用于表示接聽人,因?yàn)閱T工分三種妇斤,所以我們需要將 Employee 定義為一個(gè)抽象類摇锋,用于封裝員工的共同屬性。既然各個(gè)類模型已經(jīng)想好了站超,那么就要想想如何設(shè)計(jì)方法呢荸恕?也就是如何實(shí)現(xiàn)電話的傳遞呢?想想 Java 中是如何模仿指針效果的死相?下面來(lái)看看實(shí)現(xiàn)
public class Caller {
private String mName;
private String mRank;
public Caller(String rank) {
this.mRank = rank;
}
public String getName() {
return mName;
}
public void setName(String name) {
this.mName = name;
}
public String getRank() {
return mRank;
}
public void setRank(String rank) {
mRank = rank;
}
public void disconnect() {
System.out.println("Caller : disconnect");
}
}
以上為 Caller
方法融求,只有一個(gè)帶問題等級(jí)參數(shù)的構(gòu)造函數(shù),用于表示呼叫者必須首先聲明自己?jiǎn)栴}的等級(jí)算撮。還有一個(gè) disconnect()
方法生宛,當(dāng)呼叫者問題被處理完畢后調(diào)用,表示掛掉電話肮柜。
public abstract class Employee {
protected Employee mBoss;
public abstract void setBoss(Employee boss);
public abstract void handleCall(Call call);
}
以上是一個(gè)抽象類陷舅,定義了一個(gè)屬性和兩個(gè)方法, setBoss()
用于設(shè)置當(dāng)前員工的頂頭上司审洞,handleCall()
方法在員工接聽電話時(shí)調(diào)用莱睁。下面來(lái)看看 接線員類的實(shí)現(xiàn)
public class Respondent extends Employee {
@Override
public void handleCall(Call call) {
if (call.getCaller().getRank().equals("S")) {
System.out.println("Respondent : handle this call");
call.getCaller().disconnect();
} else {
mBoss.handleCall(call);
}
}
@Override
public void setBoss(Employee boss) {
mBoss = boss;
}
}
以上實(shí)現(xiàn)表明,setBoss()
方法必須在 handleCall()
方法之前調(diào)用芒澜,否則會(huì)報(bào)空指針錯(cuò)誤缩赛,因?yàn)樵?handleCall()
方法邏輯中,我們?cè)O(shè)置了撰糠,如果該員工能處理指定信息酥馍,則進(jìn)行處理,處理完之后呼叫者掛斷電話阅酪。如果不能處理旨袒,就將該呼叫傳遞給自己的頂頭上司汁针,交給他去處理。需要注意的是對(duì)于 Manager
類的實(shí)現(xiàn)砚尽,由于它已經(jīng)沒有上司施无,所以在handleCall()
方法中做特殊處理,如下所示
@Override
public void handleCall(Call call) {
if (call.getCaller().getRank().equals("SSS")) {
System.out.println("Manager : handle this call");
call.getCaller().disconnect();
} else {
System.out.println("We can not handle this call");
}
}
這里如果經(jīng)理也處理不了該通話必孤,只能打印不能處理該問題猾骡,不能再往上傳遞,否則會(huì)報(bào)空指針錯(cuò)誤敷搪。
下面來(lái)看看 Call
類是如何實(shí)現(xiàn)的
public class Call {
private Caller mCaller;
private Employee mEmployee;
public Call(Caller caller) {
this.mCaller = caller;
}
public Caller getCaller() {
return mCaller;
}
public void handle() {
mEmployee.handleCall(this);
}
public void setRespondent(Employee respondent) {
mEmployee = respondent;
}
}
在這里兴想,我們有一個(gè) setRespondent()
方法,這里設(shè)置的員工是接線員赡勘,因?yàn)橹挥羞@樣才可以確保如果該通話無(wú)法被處理向上傳遞嫂便。看到這里闸与,感覺這種模式就像踢皮球一樣毙替,你踢給我,我踢給你践樱,當(dāng)然也可以這么形容厂画,這種模式的實(shí)現(xiàn)思想和指針類似。
其實(shí)拷邢,我們已經(jīng)在很多地方見到過這種模式袱院,比如說 Java
的異常機(jī)制,如果一個(gè)地方拋出了異常解孙,會(huì)首先尋找距離最近的 catch
語(yǔ)句坑填,如果可以處理,就處理弛姜,不可以處理脐瑰,就再往上拋,直到可以被處理為止廷臼。
再比如說 Android
當(dāng)中的觸摸事件苍在,也是從容器中一級(jí)一級(jí)向下傳,直到傳到最底層的 View 視圖荠商,當(dāng)然傳到其中的任何一個(gè)容器的時(shí)候寂恬,都可以截?cái)噙@種傳遞。
我所理解的職責(zé)鏈模式就是如此莱没,如果有什么錯(cuò)誤的地方初肉,希望予以指正,互相學(xué)習(xí)饰躲。