设计模式(十二)责任链模式
最后更新于:2022-04-01 11:05:29
### 一、击鼓传花
击鼓传花是一种热闹而又紧张的饮酒游戏。在酒宴上宾客一次坐定位置,由一人击鼓,击鼓的地方与传花的地方是分开的,以示公正。开始击鼓时,花束就开始依次传递,鼓声一落,如果花束在某人手中,则该人就得饮酒。
比如说,贾母、贾赦、贾政、贾宝玉和贾环是五个参加击鼓传花游戏的传花者,他们组成一个环链。击鼓者将花传给贾母,开始传花游戏。花由贾母传给贾赦,贾赦传给贾政,贾政传给贾宝玉,贾宝玉传给贾环,贾环再传给贾母,由此往复,如下图所示。
![这里写图片描述](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-04-21_571890ece22b0.jpg "")
击鼓传花便是一种典型的责任链模式。
### 二、什么是责任链模式
责任链模式是一种对象的行为模式。在责任链模式里,很多对象由每一个对象对其下家的引用而连接起来形成一条链。请求在这个链上传递,直到链上的某一个对象决定处理此请求。发出这个请求的客户端并不知道链上的哪一个对象最终处理这个请求,这使得系统可以在不影响客户端的情况下动态地重新组织和分配责任。
### 三、责任链模式的结构
![这里写图片描述](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-04-21_571890ed0cc4a.jpg "")
● 抽象处理者(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)