### 一、擊鼓傳花
擊鼓傳花是一種熱鬧而又緊張的飲酒游戲。在酒宴上賓客一次坐定位置,由一人擊鼓,擊鼓的地方與傳花的地方是分開的,以示公正。開始擊鼓時,花束就開始依次傳遞,鼓聲一落,如果花束在某人手中,則該人就得飲酒。
比如說,賈母、賈赦、賈政、賈寶玉和賈環是五個參加擊鼓傳花游戲的傳花者,他們組成一個環鏈。擊鼓者將花傳給賈母,開始傳花游戲。花由賈母傳給賈赦,賈赦傳給賈政,賈政傳給賈寶玉,賈寶玉傳給賈環,賈環再傳給賈母,由此往復,如下圖所示。

擊鼓傳花便是一種典型的責任鏈模式。
### 二、什么是責任鏈模式
責任鏈模式是一種對象的行為模式。在責任鏈模式里,很多對象由每一個對象對其下家的引用而連接起來形成一條鏈。請求在這個鏈上傳遞,直到鏈上的某一個對象決定處理此請求。發出這個請求的客戶端并不知道鏈上的哪一個對象最終處理這個請求,這使得系統可以在不影響客戶端的情況下動態地重新組織和分配責任。
### 三、責任鏈模式的結構

● 抽象處理者(Handler)角色:定義出一個處理請求的接口。如果需要,接口可以定義 出一個方法以設定和返回對下家的引用。這個角色通常由一個Java抽象類或者Java接口實現。上圖中Handler類的聚合關系給出了具體子類對下家的引用,抽象方法handleRequest()規范了子類處理請求的操作。
● 具體處理者(ConcreteHandler)角色:具體處理者接到請求后,可以選擇將請求處理掉,或者將請求傳給下家。由于具體處理者持有對下家的引用,因此,如果需要,具體處理者可以訪問下家。
### 四、責任鏈模式的實例
我為更清楚的看出責任鏈模式的結構,我們先來看一看最簡答的代碼實現。
~~~
package com.designpattern.pre1;
/**
* 抽象處理者,定義處理者的接口
*
* @author 98583
*
*/
public abstract class Handler {
/**
* 下一個處理者
*/
protected Handler successor;
/**
* 每個處理者的處理方法
*/
public abstract void handleRequest();
/**
* 設置下一個處理者
*
* @param successor
*/
public void setSuccessor(Handler successor) {
this.successor = successor;
}
/**
* 獲取下一個處理者
*
* @return
*/
public Handler getSuccessor() {
return successor;
}
}
~~~
~~~
package com.designpattern.pre1;
/**
* 具體處理者
*
* @author 98583
*
*/
public class ConcreteHandler extends Handler {
/**
* 處理方法
*/
public void handleRequest() {
/**
* 如果有下一個處理者就交給下一個處理者,但是實際情況中應該判斷這個處理者能否處理這個問題,不能處理才傳給下一個處理者
*/
if (getSuccessor() != null) {
System.out.println("The request is passed to " + getSuccessor());
getSuccessor().handleRequest();
}// 在這個處理者中處理
else {
System.out.println("The request is handled here.");
}
}
}
~~~
~~~
package com.designpattern.pre1;
public class Client {
static private Handler handler1, handler2;
public static void main(String[] args) {
/**
* 定義兩個處理者
*/
handler1 = new ConcreteHandler();
handler2 = new ConcreteHandler();
handler1.setSuccessor(handler2);
handler1.handleRequest();
}
}
~~~
現在了解了責任鏈模式的基本結構,我們可以來實現上邊的紅樓夢中的擊鼓傳花的故事了。
~~~
package com.designpattern.chainofresp;
/**
* 相當于抽象的Handler
* @author 98583
*
*/
abstract class Player {
abstract public void handle(int i);
/**
* 下一位處理者
*/
private Player successor;
public Player() {
successor = null;
}
/**
* 設置下一個處理者
* @param aSuccessor
*/
protected void setSuccessor(Player aSuccessor) {
successor = aSuccessor;
}
/**
* 傳給下一個處理者,這個方法本不應該出現在這,因為每個處理者中都有這個方法,所以就放到父類中來了
* @param index
*/
public void next(int index) {
if (successor != null) {
successor.handle(index);
} else {
System.out.println("Program terminated.");
}
}
}
~~~
~~~
package com.designpattern.chainofresp;
/**
* 賈母的類相當于ConcreteHandler
* @author 98583
*
*/
class JiaMu extends Player {
public JiaMu(Player aSuccessor) {
this.setSuccessor(aSuccessor);
}
/**
* 這個處理和的處理方法
*/
public void handle(int i) {
if (i == 1) {
System.out.println("Jia Mu gotta drink!");
} else {
System.out.println("Jia Mu passed!");
/**
* 傳給下一個處理者
*/
next(i);
}
}
}
~~~
其他人的類與賈母的類相似,不再貼出,最后附上源碼。
~~~
package com.designpattern.chainofresp;
/**
* 擊鼓者,相當于客戶端
* @author 98583
*
*/
public class DrumBeater
{
private static Player player;
static public void main(String[] args)
{
JiaMu jiaMu = new JiaMu(null);
jiaMu.setSuccessor( new JiaShe (
new JiaZheng(
new JiaBaoYu(
new JiaHuan( jiaMu ) ) ) ) );
player = jiaMu;
player.handle(4);
}
}
~~~
### 五、責任鏈模式
**優點:**
- 降低耦合度
- 可簡化對象的相互連接
- 增強給對象指派職責的靈活性
- 增加新的請求處理類很方便
**缺點:**
- 不能保證請求一定被接收
- 系統性能將受到一定影響,而且在進行代碼調試時不太方便;可能會造成循環調用
### 六、適用環境
1、有多個對象可以處理同一個請求,具體哪個對象處理該請求由運行時刻自動確定。
2、在不明確指定接收者的情況下,向多個對象中的一個提交一個請求。
3、可動態指定一組對象處理請求
[http://download.csdn.net/detail/xingjiarong/9329017](http://download.csdn.net/detail/xingjiarong/9329017)
- 前言
- 設計原則(一)"開-閉"原則(OCP)
- 設計原則(二)里氏替換原則(LSP)
- 設計原則(三)組合復用原則
- 設計原則(四)依賴倒置原則(DIP)
- 設計模式(一)簡單工廠模式
- 設計模式(二)工廠方法模式
- 設計模式(三)抽象工廠模式
- 設計模式(四)單例模式
- 設計模式(五)創建者模式(Builder)
- 設計模式(六)原型模式
- 設計模式(七)門面模式(Facade Pattern 外觀模式)
- 設計模式(八)橋梁模式(Bridge)
- 設計模式(九)裝飾模式(Decorator)
- 設計模式(十)適配器模式
- 設計模式(十一)策略模式
- 設計模式(十二)責任鏈模式
- 設計模式之UML(一)類圖以及類間關系(泛化 、實現、依賴、關聯、聚合、組合)
- 設計模式之橋梁模式和策略模式的區別