责任链模式/Chain Of Responsibility
意图/适用场景:
在责任链模式里,很多对象由每一个对象对其下家的引用而连接起来形成一条链。请求在这个链上传递,直到链上的某一个对象决定处理此请求。发出这个请求的客户端并不知道链上的哪一个对象最终处理了这个请求,这使得系统可以在不影响客户端的情况下动态地重新组织链和分配责任。
UML:
参与者:
- 抽象处理者(Handler):定义出一个处理请求和管理责任链的接口。
- 具体处理者(ConcreteHandler):实现Handler的接口。它的功能是,要么把请求处理掉,要么把请求传给下家。
扩展:
理论上,一个纯的责任链模式要求一个具体的处理者对象只能在两个行为中选择一个:或者承担责任,或者把责任推给下家。而且每一个请求最终都会被某一个合适的处理者处理掉。
但在实际应用中,这两个条件可能都并不满足。一个处理者可能对请求做了一些处理之后仍然把它传给下家。一个请求也可能找不到一个合适的处理者,最终没有被任何处理者所处理而被“扔掉”。
应用实例:
还记得早期的AWT 1.0编程吗?当处理一个窗口事件时,在事件处理方法中你必须要返回一个true或者false,AWT系统以此来决定是否继续把事件传递给其它监听者来处理。
这就是责任链模式的一种应用。由于视窗构件往往位于容器构件内,因此当事件发生在一个构件上时,此构件的事件处理者可以处理此事件,然后决定是否将事件向上级窗口构件传播。上级窗口构件接到事件后,可以在此处理事件,或者决定是否再次将事件向更上一级窗口构件传播。如此往复,直到事件到达顶层构件。
AWT 1.0的这种方式也暴露出此模式的一些缺点:
- 事件处理模式是基于继承的。所有事件处理器者继承自同一个基类,并且需要转换掉同一个事件处理方法,比如handleEvent()。继承关系的缺点在于不灵活,应该尽量地使用委派关系。过多地继承还可能导致维护成本上升。
- 待处理事件会沿着责任链逐级传播,如果链路较长,而且每一级的处理时间又比较长,会使得事件处理得很慢。
示例代码:
[java]
// Source code from file:ConcreteHandlerA.java
packagedesignPatterns.ChainOfResponsibility;
publicclass ConcreteHandlerA extends Handler {
publicvoid handleRequest(Request request) {
if(request.data < 0)
System.out.println("ConcreteHandlerA.handleRequest() as data < 0");
else{
Handler successor = getSuccessor();
if(null != successor)
successor.handleRequest(request);
}
}
}
// Source code from file:ConcreteHandlerB.java
packagedesignPatterns.ChainOfResponsibility;
publicclass ConcreteHandlerB extends Handler {
publicvoid handleRequest(Request request) {
if(request.data >= 0)
System.out.println("ConcreteHandlerB.handleRequest() as data >= 0");
else{
Handler successor = getSuccessor();
if(null != successor)
successor.handleRequest(request);
}
}
}
// Source code from file:Handler.java
packagedesignPatterns.ChainOfResponsibility;
publicabstract class Handler {
privateHandler successor = null;
publicvoid setSuccessor(Handler successor) {
this.successor= successor;
}
publicHandler getSuccessor() {
returnsuccessor;
}
publicabstract void handleRequest(Request request);
}
// Source code from file:Request.java
packagedesignPatterns.ChainOfResponsibility;
publicclass Request {
intdata;
publicRequest(int data) {
this.data= data;
}
}
// Source code from file:User.java
packagedesignPatterns.ChainOfResponsibility;
publicclass User {
publicstatic void main(String[] args) {
Handler handler =new ConcreteHandlerA();
handler.setSuccessor(newConcreteHandlerB());
handler.handleRequest(newRequest(1));
}
}
[/java]