一、責任鏈模式介紹
責任鏈模式:將能夠處理同一類請求的對象連成一條鏈,使這些對象都有機會處理請求,所提交的請求沿着鏈傳遞。從而避免請求的
發送者和接受者之間的耦合關系。鏈上的對象逐個判斷是否有能力處理該請求,如果能則就處理,如果不能,則傳給鏈上的下一個對象。
直到有一個對象處理它為止。
場景:
1、打牌時,輪流出牌
2、接力賽跑
3、請假審批
4、公文審批
責任鏈UML圖:
Handler:表示處理請求的接口,在這個接口里可以定義鏈上的下一個繼承者,和一個處理請求的抽象方法。
ConcreteHandler1和ConcreteHandler2:表示具體的處理者
二、責任鏈模式代碼實現
這里以請假的流程為例,用責任鏈模式來實現
首先這里定義一個請假信息的對象
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
|
/**
* 請假的基本信息
*/
public
class
LeaveRequest {
private
String empName;
//請假人
private
int
leaveDays;
//請假天數
private
String reason;
//請假理由
public
LeaveRequest(String empName,
int
leaveDays, String reason) {
super
();
this
.empName = empName;
this
.leaveDays = leaveDays;
this
.reason = reason;
}
public
String getEmpName() {
return
empName;
}
public
void
setEmpName(String empName) {
this
.empName = empName;
}
public
int
getLeaveDays() {
return
leaveDays;
}
public
void
setLeaveDays(
int
leaveDays) {
this
.leaveDays = leaveDays;
}
public
String getReason() {
return
reason;
}
public
void
setReason(String reason) {
this
.reason = reason;
}
}
|
然后定義一個抽象類,來處理各個請求之間的關系。也就是UML圖中的Handler部分
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
/**
* 抽象類:管理責任鏈上的對象處理的抽象類
*/
public
abstract
class
Leader {
protected
String name;
protected
Leader nextLeader;
//下一個繼承者
public
Leader(String name) {
super
();
this
.name = name;
}
//設置責任鏈上的下一個繼承者
public
void
setNextLeader(Leader nextLeader) {
this
.nextLeader = nextLeader;
}
//處理請求的抽象方法
public
abstract
void
handleRequest(LeaveRequest leader);
}
|
接下來就可以開始定義處理請求的具體對象了,比如處理請假信息的:主任,經理,總經理等等。這些對象都必須繼承抽象類,來處理請求。
主任對象:處理小於等於3天的假期
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
|
//主任
public
class
Director
extends
Leader {
public
Director(String name) {
super
(name);
}
/**
* 責任鏈上對象對請求的具體處理
*/
@Override
public
void
handleRequest(LeaveRequest leader) {
if
(leader.getLeaveDays()<=
3
) {
System.out.println(
"請假人:"
+leader.getEmpName()+
",天數:"
+leader.getLeaveDays()+
",理由:"
+leader.getReason());
System.out.println(
"審批人:"
+
this
.name+
" 主任,審批通過!"
);
}
else
{
if
(
this
.nextLeader !=
null
) {
//如果有下一個繼承者
//讓下一個繼承者處理請求
this
.nextLeader.handleRequest(leader);
}
}
}
}
|
經理對象:處理大於3天,小於等於10天的假期
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
|
//經理
public
class
Manager
extends
Leader {
public
Manager(String name) {
super
(name);
}
/**
* 責任鏈上對象對請求的具體處理
*/
@Override
public
void
handleRequest(LeaveRequest leader) {
if
(leader.getLeaveDays()<=
10
) {
System.out.println(
"請假人:"
+leader.getEmpName()+
",天數:"
+leader.getLeaveDays()+
",理由:"
+leader.getReason());
System.out.println(
"審批人:"
+
this
.name+
" 經理,審批通過!"
);
}
else
{
if
(
this
.nextLeader !=
null
) {
//如果有下一個繼承者
//讓下一個繼承者處理請求
this
.nextLeader.handleRequest(leader);
}
}
}
}
|
總經理對象:處理大於等於10天,小於30天的請假信息
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
|
//總經理
public
class
GeneralManager
extends
Leader {
public
GeneralManager(String name) {
super
(name);
}
/**
* 責任鏈上對象對請求的具體處理
*/
@Override
public
void
handleRequest(LeaveRequest leader) {
if
(leader.getLeaveDays()<=
30
) {
System.out.println(
"請假人:"
+leader.getEmpName()+
",天數:"
+leader.getLeaveDays()+
",理由:"
+leader.getReason());
System.out.println(
"審批人:"
+
this
.name+
" 總經理,審批通過!"
);
}
else
{
// if (this.nextLeader != null ) {//如果有下一個繼承者
// //讓下一個繼承者處理請求
// this.nextLeader.handleRequest(leader);
// }
//總經理上面沒人了,所以不往下發送請求。
System.out.println(
"請假申請,最終不通過!最終審批人:"
+
this
.name+
" 總經理"
);
}
}
}
|
重要代碼都寫完了,下面開始測試:
1
2
3
4
5
6
7
8
9
10
11
12
13
|
public
static
void
main(String[] args) {
//構建各個領導人
Leader a =
new
Director(
"張三"
);
//主任
Leader b =
new
Manager(
"李四"
);
//經理
Leader c =
new
GeneralManager(
"王五"
);
//總經理
//設置各個責任鏈上的關系
a.setNextLeader(b);
//主任的下一個審批人為經理
b.setNextLeader(c);
//經理的下一個審批人為總經理
//開始請假
LeaveRequest request =
new
LeaveRequest(
"小明"
,
3
,
"旅游"
);
a.handleRequest(request);
//小明提交了請假申請給主任
}
|
控制台則打印:主任審批
請假人:小明,天數:3,理由:旅游
審批人:張三 主任,審批通過!
如果改成13天:則就是總經理審批
請假人:小明,天數:13,理由:旅游
審批人:王五 總經理,審批通過!
此時,我們發現,責任鏈上漏掉了副總經理,那也很好辦。直接加上副總經理就行了
增加一個副總經理的對象
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
|
package
com.fz.chainOfResponsibility;
/**
* 副總經理
*/
public
class
ViceGeneralManager
extends
Leader {
public
ViceGeneralManager(String name) {
super
(name);
}
/**
* 責任鏈上對象對請求的具體處理
*/
@Override
public
void
handleRequest(LeaveRequest leader) {
if
(leader.getLeaveDays()<=
20
) {
System.out.println(
"請假人:"
+leader.getEmpName()+
",天數:"
+leader.getLeaveDays()+
",理由:"
+leader.getReason());
System.out.println(
"審批人:"
+
this
.name+
" 副總經理,審批通過!"
);
}
else
{
if
(
this
.nextLeader !=
null
) {
//如果有下一個繼承者
//讓下一個繼承者處理請求
this
.nextLeader.handleRequest(leader);
}
}
}
}
|
測試的代碼呢,構造副總經理對象。然后再設置繼承者的關系
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
public
static
void
main(String[] args) {
//構建各個領導人
Leader a =
new
Director(
"張三"
);
//主任
Leader b =
new
Manager(
"李四"
);
//經理
//增加副總經理
Leader b2 =
new
ViceGeneralManager(
"趙四"
);
//副總經理
Leader c =
new
GeneralManager(
"王五"
);
//總經理
//設置各個責任鏈上的關系
a.setNextLeader(b);
//主任的下一個審批人為經理
b.setNextLeader(b2);
//經理的下一個審批人為副總經理
b2.setNextLeader(c);
//副總經理的下一個審批人為總經理
//開始請假
LeaveRequest request =
new
LeaveRequest(
"小明"
,
19
,
"旅游"
);
a.handleRequest(request);
//小明提交了請假申請給主任
}
|
測試結果就是:副總經理審批
請假人:小明,天數:19,理由:旅游
審批人:趙四 副總經理,審批通過!
三、責任鏈模式總結
實現方式:
1、鏈表方式:比如剛才的請假審批
2、非鏈表方式:通過集合,數組生成責任鏈更加實用,將鏈表上的各個對象都添加到集合中,然后通過反射給構建出來。
然后在容器里一個個的處理。(也就是說把測試代碼中除了請假的其他代碼都給用一個類來處理)
開發中常見場景:
1、Java的異常機制就是一個責任鏈模式,一個try可以對應多個cathc。如果某一個catch不匹配,則跳到下一個catch中
2、JavaScript語言中的事件的冒泡和捕獲機制
3、Servlet開發中,過濾器的鏈式處理
4、Struts2中,攔截器的調用也是典型的責任鏈模式
責任鏈的好處:
1、接受者和發送者都沒有對方的明確信息,且鏈中的對象也並不知道鏈的結構,結果是責任鏈可簡化對象的相互連接,它們僅需保持一個指向其
后繼者的引用,而不需要保持它所有的候選繼承者,大大的降低了耦合度。
請求者不用管具體哪個對象會處理,反正該請求肯定會被處理就行了
2、可以隨時增加或者修改處理一個請求的結構,增加了給對象指派職責的靈活性
參考資料:
大話設計模式(帶目錄完整版).pdf
HEAD_FIRST設計模式(中文版).pdf
尚學堂_高淇_java300集最全視頻教程_【GOF23設計模式】