系列文章
【設(shè)計(jì)模式】七大設(shè)計(jì)原則
【設(shè)計(jì)模式】第一章:?jiǎn)卫J?br>【設(shè)計(jì)模式】第二章:工廠模式
【設(shè)計(jì)模式】第三章:建造者模式
【設(shè)計(jì)模式】第四章:原型模式
【設(shè)計(jì)模式】第五章:適配器模式
【設(shè)計(jì)模式】第六章:裝飾器模式
【設(shè)計(jì)模式】第七章:代理模式
【設(shè)計(jì)模式】第八章:橋接模式
【設(shè)計(jì)模式】第九章:外觀模式 / 門面模式
【設(shè)計(jì)模式】第十章:組合模式
【設(shè)計(jì)模式】第十一章:享元模式
【設(shè)計(jì)模式】第十二章:觀察者模式
【設(shè)計(jì)模式】第十三章:模板方法模式
【設(shè)計(jì)模式】第十四章:策略模式
【設(shè)計(jì)模式】第十五章:責(zé)任鏈模式
【設(shè)計(jì)模式】第十六章:迭代器模式
【設(shè)計(jì)模式】第十七章:狀態(tài)模式
【設(shè)計(jì)模式】第十八章:備忘錄模式
【設(shè)計(jì)模式】第十九章:訪問(wèn)者模式
【設(shè)計(jì)模式】第二十章:解釋器模式
【設(shè)計(jì)模式】第二十一章:命令模式
【設(shè)計(jì)模式】第二十二章:中介者模式
一、定義
摘自百度百科: 在責(zé)任鏈模式里,很多對(duì)象由每一個(gè)對(duì)象對(duì)其下家的引用而連接起來(lái)形成一條鏈。請(qǐng)求在這個(gè)鏈上傳遞,直到鏈上的某一個(gè)對(duì)象決定處理此請(qǐng)求。發(fā)出這個(gè)請(qǐng)求的客戶端并不知道鏈上的哪一個(gè)對(duì)象最終處理這個(gè)請(qǐng)求,這使得系統(tǒng)可以在不影響客戶端的情況下動(dòng)態(tài)地重新組織和分配責(zé)任。
二、角色分類
抽象處理者(Handler)
定義了處理請(qǐng)求的接口或者抽象類,并提供了處理請(qǐng)求的的方法和設(shè)置下一個(gè)處理者的方法
具體處理者(Concrete Handler)
它是抽象處理者的子類,可以處理用戶請(qǐng)求,在具體處理者類中實(shí)現(xiàn)了抽象處理者中定義的抽象請(qǐng)求處理方法,在處理請(qǐng)求之前需要進(jìn)行判斷,看是否有相應(yīng)的處理權(quán)限,如果可以處理請(qǐng)求就處理它,否則將請(qǐng)求轉(zhuǎn)發(fā)給后繼者;在具體處理者中可以訪問(wèn)鏈中下一個(gè)對(duì)象,以便請(qǐng)求的轉(zhuǎn)發(fā)
客戶角色(Client)
具體調(diào)用方法的角色
三、實(shí)現(xiàn)方式
UML圖
具體實(shí)現(xiàn)
假如我們想用責(zé)任鏈模式實(shí)現(xiàn)一個(gè)請(qǐng)假流程,可以這么來(lái)實(shí)現(xiàn)
抽象處理者(Handler)
@Data
public abstract class Handler {
// 處理者姓名
protected String processorName;
// 下一個(gè)處理者
protected Handler nextHandler
public Handler (String processorName) {
this.processorName = processorName;
}
/**
* 處理請(qǐng)假抽象方法
* @param name 請(qǐng)假人姓名
* @param numOfDays 請(qǐng)假天數(shù)
*/
public abstract boolean process(String name, int numOfDays);
}
具體處理者(Concrete Handler)
/**
* 組長(zhǎng)
*/
@Slf4j
public class TeamLeaderHandler extends Handler {
public TeamLeaderHandler(String processorName) {
this.processorName = processorName;
}
@Override
public boolean process(String name, int numOfDays) {
// 創(chuàng)建隨機(jī)數(shù),值大于3則為通過(guò),否則為不通過(guò)
boolean res = (new Random().nextInt(10)) > 3;
String result = res ? "通過(guò)" : "駁回";
log.info("組長(zhǎng)<{}>審批<{}>的請(qǐng)假申請(qǐng),請(qǐng)假天數(shù)為:<{}>天,審批結(jié)果為:<{}>", processorName, name, numOfDays, result);
if(Boolean.FALSE.equals(res)) {
// 審批駁回
return false;
} else if (numOfDays < 3){
// 請(qǐng)假通過(guò)且請(qǐng)假天數(shù)小于3天時(shí)直接通過(guò)
return true;
}
// 若審批通過(guò)且請(qǐng)假天數(shù)大于等于3天時(shí)提交給下一個(gè)審批人
return nextHandler.process(name, numOfDays);
}
}
/**
* 部門經(jīng)理
*/
@Slf4j
public class DepartmentManagerHandler extends Handler {
public DepartmentManagerHandler(String processorName) {
super(name);
}
@Override
public boolean process(String name, int numOfDays) {
// 創(chuàng)建一個(gè)隨機(jī)數(shù) 當(dāng)隨機(jī)數(shù)大于3時(shí)為通過(guò),否則為不通過(guò)
boolean res = (new Random().nextInt(10)) > 3;
String result = result ? "通過(guò)" : "駁回";
log.info("部門經(jīng)理<{}>審批<{}>的請(qǐng)假申請(qǐng),請(qǐng)假天數(shù)為:<{}>天,審批結(jié)果為:<{}>", processorName, name, numOfDays, result);
if(Boolean.FALSE.equals(res)) {
// 審批駁回
return false;
} else if (numOfDays <7) {
// 審批通過(guò)且審批天數(shù)小于7天時(shí)直接通過(guò)
return true;
}
// 批準(zhǔn)天數(shù)大于等于7天時(shí)提交給下一個(gè)審批人
return nextHandler.process(name, numOfDays);
}
/**
* CEO
*/
@Slf4j
public class CEOHandler extends Handler {
public CEOHandler(String processorName) {
super(name);
}
public boolean process(String name, int numOfDays) {
// 創(chuàng)建一個(gè)隨機(jī)數(shù),大于3則為通過(guò),否則為駁回
boolean res = (new Random().nextInt(10)) > 3;
String result = res ? "通過(guò)" : "駁回";
log.info("CEO<{}>審批<{}>的請(qǐng)假申請(qǐng),請(qǐng)假天數(shù)為:<{}>天,審批結(jié)果為:<{}>", processorName, name, numOfDays, result);
if(Boolean.FALSE.equals(res)) {
//駁回
return false;
}
return true;
}
}
}
客戶角色(Client)
public class Client {
public static void main(String[] args) {
Handler zhangsan = new TeamLeaderHandler("張三");
Handler lisi = new DepartmentManagerHandler("李四");
Handler wangwu = new CEOHandler("王五");
// 創(chuàng)建責(zé)任鏈
zhangsan.setNextHandler(lisi);
lisi.setNextHandler(wangwu);
// 發(fā)起請(qǐng)假申請(qǐng)
boolean res1 = zhangsan.process("小A", 2);
System.out.println("最終結(jié)果:" + res);
boolean res1 = zhangsan.process("小B", 5);
System.out.println("最終結(jié)果:" + res);
boolean res1 = zhangsan.process("小C", 10);
System.out.println("最終結(jié)果:" + res);
}
}
運(yùn)行結(jié)果
組長(zhǎng)<張三>審批<小A>的請(qǐng)假申請(qǐng),請(qǐng)假天數(shù)為:<2>天,審批結(jié)果為:<通過(guò)>
最終結(jié)果:true
部門經(jīng)理<李四> 審批 <小B> 的請(qǐng)假申請(qǐng),請(qǐng)假天數(shù): <5>天 ,審批結(jié)果:<不通過(guò)>
最終結(jié)果:false
組長(zhǎng)<張三> 審批 <小C> 的請(qǐng)假申請(qǐng),請(qǐng)假天數(shù): <10> 天,審批結(jié)果:<通過(guò)>
部門經(jīng)理<李四> 審批 <小C> 的請(qǐng)假申請(qǐng),請(qǐng)假天數(shù): <10> 天,審批結(jié)果:<通過(guò)>
CEO<王五> 審批 <小C> 的請(qǐng)假申請(qǐng),請(qǐng)假天數(shù): <10> 天,審批結(jié)果:<通過(guò)>
最終結(jié)果:true
四、應(yīng)用場(chǎng)景
以下部分內(nèi)容摘自菜鳥教程
意圖: 避免請(qǐng)求發(fā)送者與接收者耦合在一起,讓多個(gè)對(duì)象都有可能接收請(qǐng)求,將這些對(duì)象連接成一條鏈,并且沿著這條鏈傳遞請(qǐng)求,直到有對(duì)象處理它為止。
主要解決: 職責(zé)鏈上的處理者負(fù)責(zé)處理請(qǐng)求,客戶只需要將請(qǐng)求發(fā)送到職責(zé)鏈上即可,無(wú)須關(guān)心請(qǐng)求的處理細(xì)節(jié)和請(qǐng)求的傳遞,所以職責(zé)鏈將請(qǐng)求的發(fā)送者和請(qǐng)求的處理者解耦了。
何時(shí)使用: 在處理消息的時(shí)候以過(guò)濾很多道。
如何解決: 攔截的類都實(shí)現(xiàn)統(tǒng)一接口。
關(guān)鍵代碼: Handler 里面聚合它自己,在 HandlerRequest 里判斷是否合適,如果沒(méi)達(dá)到條件則向下傳遞,向誰(shuí)傳遞之前 set 進(jìn)去。
應(yīng)用實(shí)例:
- 紅樓夢(mèng)中的"擊鼓傳花"。
- JS 中的事件冒泡。
- JAVA WEB 中 Apache Tomcat 對(duì) Encoding 的處理,Struts2 的攔截器,jsp servlet 的 Filter。
使用場(chǎng)景:
- 有多個(gè)對(duì)象可以處理同一個(gè)請(qǐng)求,具體哪個(gè)對(duì)象處理該請(qǐng)求由運(yùn)行時(shí)刻自動(dòng)確定。
- 在不明確指定接收者的情況下,向多個(gè)對(duì)象中的一個(gè)提交一個(gè)請(qǐng)求。
- 可動(dòng)態(tài)指定一組對(duì)象處理請(qǐng)求。
注意事項(xiàng): 在 JAVA WEB 中遇到很多應(yīng)用。
五、優(yōu)缺點(diǎn)
優(yōu)點(diǎn)
- 降低耦合度。它將請(qǐng)求的發(fā)送者和接收者解耦。
- 簡(jiǎn)化了對(duì)象。使得對(duì)象不需要知道鏈的結(jié)構(gòu)。
- 增強(qiáng)給對(duì)象指派職責(zé)的靈活性。通過(guò)改變鏈內(nèi)的成員或者調(diào)動(dòng)它們的次序,允許動(dòng)態(tài)地新增或者刪除責(zé)任。
- 增加新的請(qǐng)求處理類很方便。
缺點(diǎn)
- 不能保證請(qǐng)求一定被接收。
- 系統(tǒng)性能將受到一定影響,而且在進(jìn)行代碼調(diào)試時(shí)不太方便,可能會(huì)造成循環(huán)調(diào)用。
- 可能不容易觀察運(yùn)行時(shí)的特征,有礙于除錯(cuò)。
推薦
關(guān)注博客和公眾號(hào)獲取最新文章文章來(lái)源:http://www.zghlxwxcb.cn/news/detail-538298.html
Bummon’s Blog | Bummon’s Home | 公眾號(hào)文章來(lái)源地址http://www.zghlxwxcb.cn/news/detail-538298.html
到了這里,關(guān)于【設(shè)計(jì)模式】第十五章:責(zé)任鏈模式詳解及應(yīng)用案例的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!