简介
Advoid coupling the sender of a reuest to its receiver by giving more than one object a chance to handle the request. Chain the receiving objects and pass the request along the chain until an object handles it.
使多个对象都有机会处理请求,从而避免了请求的发送者和接收者之间的耦合关系。将这些对象连成一条链,并沿着这条链传递该请求,直到有一个对象处理它为止。
责任链模式(Chain of Responsibility) 是行为型设计模式之一,其将链中每一个节点看作是一个对象,每个节点处理的请求均不同,且内部自动维护一个下一节点对象。当一个请求从链式的首端发出时,会沿着链的路径依次传递给每一个节点对象,直至有对象处理这个请求为止。
主要解决
责任链模式 解耦了请求与处理,客户只需将请求发送到链上即可,无需关心请求的具体内容和处理细节,请求会自动进行传递直至有节点对象进行处理。
优缺点
优点
- 解耦了请求与处理;
- 请求处理者(节点对象)只需关注自己感兴趣的请求进行处理即可,对于不感兴趣的请求,直接转发给下一级节点对象;
- 具备链式传递处理请求功能,请求发送者无需知晓链路结构,只需等待请求处理结果;
- 链路结构灵活,可以通过改变链路结构动态地新增或删减责任;
- 易于扩展新的请求处理类(节点),符合 开闭原则;
缺点
- 责任链路过长时,可能对请求传递处理效率有影响;
- 如果节点对象存在循环引用时,会造成死循环,导致系统崩溃;
使用场景
- 多个对象可以处理同一请求,但具体由哪个对象处理则在运行时动态决定;
- 在不明确指定接收者的情况下,向多个对象中的一个提交一个请求;
- 可动态指定一组对象处理请求;
使用场景
首先来看下 责任链模式 的通用 UML 类图:
从 UML 类图中,我们可以看到,责任链模式 主要包含两种角色:
- 抽象处理者(Handler):定义一个请求处理的方法,并维护一个下一个处理节点 Handler 对象的引用;
- 具体处理者(ConcreteHandler):对请求进行处理,如果不感兴趣,则进行转发;
以下是 责任链模式 的通用代码:
class Client {
public static void main(String[] args) {
Handler handlerA = new ConcreteHandlerA();
Handler handlerB = new ConcreteHandlerB();
handlerA.setnextHanlder(handlerB);
handlerA.handleRequest("requestB");
}
static abstract class Handler {
protected Handler mNextHandler;
public void setnextHanlder(Handler successor) {
this.mNextHandler = successor;
}
public abstract void handleRequest(String request);
}
static class ConcreteHandlerA extends Handler {
@Override
public void handleRequest(String request) {
if ("requestA".equals(request)) {
System.out.println(String.format("%s deal with request: %s", this.getClass().getSimpleName(), request));
return;
}
if (this.mNextHandler != null) {
this.mNextHandler.handleRequest(request);
}
}
}
static class ConcreteHandlerB extends Handler {
@Override
public void handleRequest(String request) {
if ("requestB".equals(request)) {
System.out.println(String.format("%s deal with request: %s", this.getClass().getSimpleName(), request));
return;
}
if (this.mNextHandler != null) {
this.mNextHandler.handleRequest(request);
}
}
}
}
上面的代码中,其实我们把消息硬编码为String
类型,而真实业务中,消息是具备多样性的,可以是int
、String
或者是自定义类型····因此,我们可以在上面代码中的基础上,将消息类型进行抽象Request
,增强了消息的包容性。
注:责任链模式 的本质是:解耦请求与处理,让请求在处理链中能进行传递与被处理;理解 责任链模式 应当理解的是其模式(道)而不是其具体实现(术),责任链模式 的独到之处是其将节点处理者组合成了链式结构,并允许节点自身决定是否进行请求处理或转发,相当于让请求流动了起来。因此,上面的通用代码中,把请求硬编码为String
,是为了更加清晰描述 责任链模式 的链式组成与请求传递实现结构原理,而下面内容所要讲述的,其实更多地是基于“术”的层面,如何让 责任链模式 更加完善。
其 UML 类图如下所示:
代码如下所示:
class Client {
public static void main(String[] args) {
// 来一个具体处理者A
Handler<String> handlerA = new ConcreteHandlerA(new ConcreteRequest("requestA"));
// 来一个具体处理者B
Handler<String> handlerB = new ConcreteHandlerB(new ConcreteRequest("requestB"));
// A的下一节点为B
handlerA.setNextHandler(handlerB);
// 来一个消息:requestA
Request<String> request = new ConcreteRequest("requestA");
// 将消息交由具体处理者A
handlerA.handleRequest(request);
System.out.println("------------------------");
// 来一个消息:requestB
request = new ConcreteRequest("requestB");
// 将消息交由具体处理者A
handlerA.handleRequest(request);
System.out.println("------------------------");
// 来一个消息:requestC
request = new ConcreteRequest("requestC");
// 将消息交由具体处理者A
handlerA.handleRequest(request);
}
// 抽象消息
static abstract class Request<T> {
private T mRequest;
public Request(T request) {
this.mRequest = request;
}
public T getRequest() {
return this.mRequest;
}
@Override
public String toString() {
return this.mRequest.toString();
}
public abstract boolean isSame(Request<T> request);
}
// 具体消息
static class ConcreteRequest extends Request<String> {
public ConcreteRequest(String request) {
super(request);
}
@Override
public boolean isSame(Request<String> request) {
return this.getRequest().equals(request.getRequest());
}
}
// 抽象处理者
static abstract class Handler<T> {
private Handler<T> mNextHandler;
private Request<T> mRequest;
public Handler(Request<T> request) {
this.mRequest = request;
}
public void setNextHandler(Handler<T> successor) {
this.mNextHandler = successor;
}
public final void handleRequest(Request<T> request) {
do {
if (this.mRequest.isSame(request)) {
this.handle(request);
break;
}
if (this.mNextHandler != null) {
this.mNextHandler.handleRequest(request);
break;
}
System.out.println("No Handlers can handle this request: " + request);
} while (false);
}
protected abstract void handle(Request<T> request);
}
// 具体处理者A
static class ConcreteHandlerA extends Handler<String> {
public ConcreteHandlerA(Request<String> request) {
super(request);
}
@Override
protected void handle(Request<String> request) {
System.out.println(String.format("%s deal with request: %s", this.getClass().getSimpleName(), request));
}
}
// 具体处理者B
static class ConcreteHandlerB extends Handler<String> {
public ConcreteHandlerB(Request<String> request) {
super(request);
}
@Override
protected void handle(Request<String> request) {
System.out.println(String.format("%s deal with request: %s", this.getClass().getSimpleName(), request));
}
}
}
运行结果如下:
ConcreteHandlerA deal with request: requestA
------------------------
ConcreteHandlerB deal with request: requestB
------------------------
No Handlers can handler this request: requestC
责任链模式 的本质是解耦请求和处理,上面的代码抽象了请求Request
和处理Hanlder
,已经很完善了,但是还可以更加完善。因为 责任链模式 具备链式结构,而上面代码中,我们看到,负责组装链式结构的角色是客户端,当链式结构较长时,客户端的工作会非常繁琐,并且客户端代码相对臃肿,且后续更改处理者或消息类型时,都必须在客户端中进行修改,不符合 开闭原则。产生这些问题的原因就是因为链式结构的组装过于复杂,而对于复杂结构的创建,很自然我们就会想到 建造者模式,使用 建造者模式,我们完全可以对客户端指定的处理节点对象进行自动链式组装,客户只需指定处理节点对象,其他任何事情都无需关心,并且客户指定的处理节点对象顺序不同,构造出来的链式结构也随之不同。
具体代码如下:
class Client {
public static void main(String[] args) {
Handler.Builder<String> builder = new Handler.Builder<String>();
List<Handler<String>> handlers = makeHanlders();
for (Handler<String> handler : handlers) {
builder.addHandler(handler);
}
Handler<String> firstHandler = builder.build();
for (int i = 0; i < 25; ++i) {
System.out.println("-----------------");
Request<String> request = makeRequest(String.format("%03d", i));
firstHandler.handleRequest(request);
}
}
private static List<Handler<String>> makeHanlders() {
List<Handler<String>> handlers = new ArrayList<>();
for (int i = 0; i < 20; ++i) {
String request = String.format("%03d", i);
handlers.add(makeHandler("handler" + request, makeRequest(request)));
}
return handlers;
}
private static Request<String> makeRequest(String request) {
return new Request<String>(request) {
@Override
public boolean isSame(Request<String> request) {
return this.getRequest().equals(request.getRequest());
}
};
}
private static Handler<String> makeHandler(final String handlerName, Request<String> request) {
return new Handler<String>(request) {
@Override
protected void handle(Request<String> request) {
System.out.println(String.format("%s deal with request: %s", handlerName, request));
}
};
}
// 抽象消息
static abstract class Request<T> {
...
...
}
// 抽象处理者
static abstract class Handler<T> {
...
...
private void setNextHandler(Handler<T> handler) {
this.mNextHandler = handler;
}
...
...
public static class Builder<T> {
private Handler<T> mFirst;
private Handler<T> mLast;
public Builder<T> addHandler(Handler<T> handler) {
do {
if (this.mFirst == null) {
this.mFirst = this.mLast = handler;
break;
}
this.mLast.setNextHandler(handler);
this.mLast = handler;
} while (false);
return this;
}
public Handler<T> build() {
return this.mFirst;
}
}
}
}
因为 建造者模式 要构建的是节点处理者,因此我们把Builder
作为Handler
的静态内部类,并且因为客户端无需进行链式组装,因此我们把链式组装方法setNextHandler
设置为private
,使Handler
更加高内聚。
运行结果如下:
-----------------
handler000 deal with request: 000
-----------------
handler001 deal with request: 001
-----------------
handler002 deal with request: 002
-----------------
handler003 deal with request: 003
-----------------
handler004 deal with request: 004
-----------------
handler005 deal with request: 005
-----------------
handler006 deal with request: 006
-----------------
handler007 deal with request: 007
-----------------
handler008 deal with request: 008
-----------------
handler009 deal with request: 009
-----------------
handler010 deal with request: 010
-----------------
handler011 deal with request: 011
-----------------
handler012 deal with request: 012
-----------------
handler013 deal with request: 013
-----------------
handler014 deal with request: 014
-----------------
handler015 deal with request: 015
-----------------
handler016 deal with request: 016
-----------------
handler017 deal with request: 017
-----------------
handler018 deal with request: 018
-----------------
handler019 deal with request: 019
-----------------
No Handlers can handle this request: 020
-----------------
No Handlers can handle this request: 021
-----------------
No Handlers can handle this request: 022
-----------------
No Handlers can handle this request: 023
-----------------
No Handlers can handle this request: 024
举个例子
例子:小明是一个初级软件开发工程师,假设现在公司有几个需求需要开发,这些需求有些比较容易,有些比较困难。开发团队中有初级工程师,中级工程师,高级工程师和资深工程师,按需求难度进行划分,初级工程师能解决就交由初级工程师,否则将需求转交到更高一级工程师,直到资深工程师。如果资深工程师都无法解决这个需求,则要求产品更改需求。
分析:以上例子是一个典型的 责任链模式 需求,工程师对应节点处理者,需求对应请求。利用 责任链模式,只需将需求一个一个交由初级工程师(小明),需求就会自动地传递给具备相应能力进行开发的工程师手中,或者需求无法解决,则交由产品更改。
具体代码如下:
class Client {
public static void main(String[] args) {
Engineer xiaoming = new Engineer.Builder()
.addEngineer(new JuniorEngineer())
.addEngineer(new MidEngineer())
.addEngineer(new SeniorEngineer())
.addEngineer(new ProfessionalEngineer())
.build();
IProject easyProject = new EasyProject();
IProject normalProject = new NormalProject();
IProject hardProject = new HardProject();
IProject tooHardProject = new TooHardProject();
IProject beyondProject = new BeyondProject();
if(!xiaoming.doWork(easyProject)){
System.out.println("tell Product Manager: easy project can not complete");
}
if(!xiaoming.doWork(normalProject)){
System.out.println("tell Product Manager: normal project can not complete");
}
if(!xiaoming.doWork(hardProject)){
System.out.println("tell Product Manager: hard project can not complete");
}
if(!xiaoming.doWork(tooHardProject)){
System.out.println("tell Product Manager: too hard project can not complete");
}
if(!xiaoming.doWork(beyondProject)){
System.out.println("tell Product Manager: beyond project can not complete: "+beyondProject.difficulty());
}
}
interface IProject {
static int EASY = 0;
static int NORMAL = 1;
static int HARD = 2;
static int TOO_HARD = 3;
static int BEYOND = 4;
// 项目难度
int difficulty();
}
static class EasyProject implements IProject{
@Override
public int difficulty() {
return IProject.EASY;
}
}
static class NormalProject implements IProject{
@Override
public int difficulty() {
return IProject.NORMAL;
}
}
static class HardProject implements IProject{
@Override
public int difficulty() {
return IProject.HARD;
}
}
static class TooHardProject implements IProject{
@Override
public int difficulty() {
return IProject.TOO_HARD;
}
}
static class BeyondProject implements IProject{
@Override
public int difficulty() {
return IProject.BEYOND;
}
}
static abstract class Engineer {
private Engineer mSuccessor;
public final boolean doWork(IProject project) {
boolean bRet = false;
do {
if (this.filterProject(project)) {
bRet = this.writeCode(project);
break;
}
if (this.mSuccessor != null) {
bRet = this.mSuccessor.doWork(project);
break;
}
} while (false);
return bRet;
}
protected abstract boolean filterProject(IProject project);
protected abstract boolean writeCode(IProject project);
public static class Builder {
private Engineer mFirst;
private Engineer mLast;
public Builder addEngineer(Engineer engineer) {
if (this.mFirst == null) {
this.mFirst = this.mLast = engineer;
} else {
this.mLast.mSuccessor = engineer;
this.mLast = engineer;
}
return this;
}
public Engineer build() {
return this.mFirst;
}
}
}
// 初级工程师
static class JuniorEngineer extends Engineer {
@Override
protected boolean filterProject(IProject project) {
return project.difficulty() <= IProject.EASY;
}
@Override
protected boolean writeCode(IProject project) {
System.out.println("Junior engineer completes project: " + project.difficulty());
return true;
}
}
// 中级工程师
static class MidEngineer extends Engineer {
@Override
protected boolean filterProject(IProject project) {
return project.difficulty() <= IProject.NORMAL;
}
@Override
protected boolean writeCode(IProject project) {
System.out.println("Middle level engineer completes project: " + project.difficulty());
return true;
}
}
// 高级工程师
static class SeniorEngineer extends Engineer {
@Override
protected boolean filterProject(IProject project) {
return project.difficulty() <= IProject.HARD;
}
@Override
protected boolean writeCode(IProject project) {
System.out.println("Senior engineer completes project: " + project.difficulty());
return true;
}
}
// 资深工程师
static class ProfessionalEngineer extends Engineer {
@Override
protected boolean filterProject(IProject project) {
return project.difficulty() <= IProject.TOO_HARD;
}
@Override
protected boolean writeCode(IProject project) {
System.out.println("Professional engineer completes project: " + project.difficulty());
return true;
}
}
}
结果如下:
Junior engineer completes project: 0
Middle level engineer completes project: 1
Senior engineer completes project: 2
Professional engineer completes project: 3
tell Product Manager: beyond project can not complete: 4