一、责任链模式的核心思想
在责任链模式里,很多对象由每一个对象对其下家的引用而连接起来形成一条链。请求在这个链上传递,直到链上的某一个对象决定处理此请求。发出这个请求的客户端并不知道链上的哪一个对象最终处理这个请求,这使系统可以在不影响客户端的情况下动态地重新组织链和分配责任。
责任链模式中包括3种对象:
- 责任链接口 Handler:定义了操作的接口方法。
- 责任链抽象类 AbstractHandler:定义一个 Handler 对象的应用,以设定和返回下家的引用。
- 责任链具体类 MyHandler:具体类实现了上面的接口并将继承抽象类,在操作函数中取得下一个引用的对象,可以选择将请求处理掉,或者将请求传给下家。由于处理者持有下家引用,因此,如果需要,具体类可以访问下家。
其结构图如下图所示:
下面来看具体的实现。
(1) 责任链接口 Handler.java需要定义一个具体的操作接口,其源代码如下程序所示。
package behavior.chainofresponsibility;
/**
* @author Minggg
* 责任链接口
*/
public interface Handler {
public void operation();
}
(2) 责任链抽象类 AtstractHandler.java定义了一个 Handler 对象,以实现对下家的引用,并提供 getter/setter 函数实现对该引用的取得和修改操作。其源代码如下程序所示。
package behavior.chainofresponsibility;
/**
* @author Minggg
* 责任链抽象类
*/
public abstract class AbstractHandler {
// 定义责任链对象
private Handler chain;
public Handler getChain() {
return chain;
}
public void setChain(Handler chain) {
this.chain = chain;
}
}
(3) 责任链类 MyHandler.java 实现了 Handler 接口,因此必须编写实现函数 operation()。在该函数中为了实现对下家的引用,必须继承自 AbstractHandler,以实现对下家的引用,并提供getter/setter函数实现对该引用的取得和修改操作,这就是责任链的核心。其源代码如下程序所示。
package behavior.chainofresponsibility;
/**
* @author Minggg
* 责任链实现类
*/
public class MyHandler extends AbstractHandler implements Handler {
private String name;
public MyHandler(String name) {
this.name = name;
}
// 操作并调用责任链对象
public void operation() {
System.out.println(name+" 处理代码");
if(getChain() != null) {
getChain().operation();
}
}
}
根据以上的实现类 MyHandler,可以创建多个实例对象,并通过 setChain()函数将它们链接起来,就形成了责任链。调用链顶端的节点可以实现对整条链的调用。如下程序所示,这里创建了3个链对象 handler1、handler2、handler3,handler1设置了链接对象 handler2,handler2 又设置了链接对象 handler3,然后调用 handler1 即可实现对整条链的调用。
package behavior.chainofresponsibility;
/**
* @author Minggg
* 测试类
*/
public class Test {
public static void main(String[] args){
MyHandler handler1 = new MyHandler("handler1");
MyHandler handler2 = new MyHandler("handler2");
// 设置链接
handler1.setChain(handler2);
MyHandler handler3 = new MyHandler("handler3");
// 设置链接
handler2.setChain(handler3)
handler1.operation();
}
}
运行该程序会依次输出各个链对象的信息:
handler1 处理代码
handler2 处理代码
handler3 处理代码
二、何时使用责任链模式
责任链模式减低了请求的发送端和接收端之间的耦合,使多个对象有机会处理这个请求。一个链可以是一条线,一个树,也可以是一个环。链的拓扑结构可以是单连通的或多连通的,责任链模式并不指定责任链的拓扑结构。但是责任链模式要求在同一时间里,命令只可以被传给一个下家(或被处理掉),而不可以传给多个下家。
责任链的成员往往是一个更大结构的一部分。如果责任链的成员不存在,那么为了使用责任链模式,就必须创建它们。责任链的具体处理者对象可以是同一个具体处理者的实例。
在一个责任链上传递的可能不只是一个命令,而是多个命令。这些命令可以采取抽象化层、具体化层的多态性实现方式,从而可以将命令对象与责任链上的对象之间的责任分隔开,并将命令对象与传播命令的对象分隔开。如果责任链上的传播命令只有一个,且是固定的命令,那么这个命令不一定要对象化。
三、Java中的应用–I/O 输人/输出流管道的责任链模式
Java的 I/O库提供了一个称做链接(Chaining)的机制,可以将一个流处理器与另一个流处理器首尾相接,以其中之一的输出为输入,形成一个流管道的链接。实际上这就是责任链模式,而且每个类还进行了不同的包装,又属于装饰器模式。
例如,DataInputStream 流处理器可以把 FileInputStream 流对象的输出当做输入,将 Byte 类型的数据转换成 Java 的原始类型和 String 类型的数据,如下图所示。
类似地,向一个文件写入 Byte 类型的数据不是一个简单的过程。一个程序需要向一个文件里写入的数据往往都是结构化的,而Byte类型则是原始类型。因此在写的时候必须经过转换。DataOutputStream 流处理器提供和接收了原始数据类型和 String 数据类型,而这个流处理器的输出数据则是 Byte 类型。也就是说 DataOutputStream 可以将源数据转换成 Byte 类型的数据,再输出来。
因此,Java I/O 库中的所有输入流、输出流的类都采用了责任链模式,它们可以无限次地进行装饰转换,转换的目标就是得到自己想要的数据类型的流对象。
由流管道的责任链模式也可以得出,凡是具有过滤和管道特征的应用都属于责任链器模式,例如 Java EE 中的 Filter 过滤器、UNIX中的管道符等,都属于责任链模式。责任链模式在软件中的应用时随处可见。