责任链模式
责任链模式:使多个对象都有机会处理请求,从而避免了请求的发送者和接受者之间的耦合关系。将这些对象连成一条链,并沿着这条链传递该请求,直到有对象处理它为止。
责任链模式的核心:作为请求者可以不用知道到底是需要谁来处理的(请求者不需要知道处理者是谁)。
责任链模式的重点是在“链”上,“链”是由多个处理者ConcreteHandler组成的,由一条链去处理相似的请求在链中决定谁来处理这个请求,并返回相应的结果。
抽象处理者Handler:
public abstract class Handler {
private Handler nextHandler;
//每个处理者都必须对请求做出处理
public final Response handleMessage(Request request){
Response response = null;
//判断是否是自己的处理级别
if(this.getHandlerLevel().equals(request.getRequestLevel())){
response = this.echo(request);
}else{ //不属于自己的处理级别
//判断是否有下一个处理者
if(this.nextHandler != null){
response = this.nextHandler.handleMessage(request);
}else{
//没有适当的处理者,业务自行处理
}
}
return response;
}
//设置下一个处理者是谁
public void setNext(Handler _handler){
this.nextHandler = _handler;
}
//每个处理者都有一个处理级别
protected abstract Level getHandlerLevel();
//每个处理者都必须实现处理任务
protected abstract Response echo(Request request);
}
抽象的处理者实现三个职责:
- 定义一个请求的处理方法handleMessage,唯一对外开放的方法;
- 定义一个链的编排方法setNext,设置下一个处理者;
- 定义了具体的请求者必须实现的两个方法:定义自己能够处理的级别getHandlerLevel和具体的处理任务echo。
具体处理者ConcreteHandler1~3:
public class ConcreteHandler1 extends Handler {
//定义自己的处理逻辑
protected Response echo(Request request) {
//完成处理逻辑
return null;
}
//设置自己的处理级别
protected Level getHandlerLevel() {
//设置自己的处理级别
return null;
}
}
public class ConcreteHandler2 extends Handler {
//定义自己的处理逻辑
protected Response echo(Request request) {
//完成处理逻辑
return null;
}
//设置自己的处理级别
protected Level getHandlerLevel() {
//设置自己的处理级别
return null;
}
}
public class ConcreteHandler3 extends Handler {
//定义自己的处理逻辑
protected Response echo(Request request) {
//完成处理逻辑
return null;
}
//设置自己的处理级别
protected Level getHandlerLevel() {
//设置自己的处理级别
return null;
}
}
在处理者中涉及三个类:
- Level类负责定义请求的处理级别;
- Request类负责封装请求;
- Response负责封装链中返回的结果。
这三个类都需要根据业务产生。
有关框架代码:
public class Level {
//定义一个请求和处理等级
}
public class Request {
//请求的等级
public Level getRequestLevel(){
return null;
}
}
public class Response {
//处理者返回的数据
}
在场景类或高层模块中对链进行组装,并传递请求,返回结果。
public class Client {
public static void main(String[] args) {
//声明所有的处理节点
Handler handler1 = new ConcreteHandler1();
Handler handler2 = new ConcreteHandler2();
Handler handler3 = new ConcreteHandler3();
//设置链中的阶段顺序1-->2-->3
handler1.setNext(handler2);
handler2.setNext(handler3);
//提交请求,返回结果
Response response = handler1.handlerMessage(new Request());
}
}
在实际应用中,一般会有一个封装类对责任模式进行封装,也就是替代Client类,直接返回链中的第一个处理者,具体链的设置不需要高层次模块关系。这样,更简化了高层次模 块的调用,减少模块间的耦合,提高系统的灵活性。
责任链模式的优点
将请求和处理分开。
责任链模式的缺点
- 性能问题。每个请求都是从链头遍历到链尾,特别是在链比较长的时候,性能是一个非常大的问题。
- 调试不方便。特别是链条较长,环节较多时,由于采用类似递归的方式,调试时逻辑可能比较复杂。
注意事项
链中节点数量需要控制,避免出现超长链的情况,一般的做法是在Handler中设置一个最大节点数量,在setNext方法中判断是否已经是超过其阈值,超过则不允许该链建立,避免 无意识地破坏系统性能。
责任链模式实例
这里采用古代女子“三从四德”中的“三从”作为实例,即“未嫁从父、既嫁从夫、夫死从子”。假设某一妇女想出门逛街,则需要多番请示。作为父亲、丈夫或儿子,只有两种选择:要不承担起责任来,允许她或不允许她逛街;要不就让她请示下一个人,这是整个社会体系的约束,应用到我们项目中就是业务规则。
我们可以设计这样一个顺序处理图:
同时得到这样一张类图:
类图中,三个实现类Father、Husband、Son只要实现构造函数和父类中的抽象方法response,具体由谁处理女性提出的请求,都转移到Handler抽象类中。
(1)IWomen接口及其实现Women类:定义并实现两个方法,分别是妇女个人状况和个人请求。
public interface IWomen {
//获得个人状况
public int getType();
//获得个人请示,要出去逛街还是约会?
public String getRequest();
}
import com.sfq.impl.IWomen;
public class Women implements IWomen {
/*
* 通过int描述妇女个人状况
* 1--未出嫁
* 2--出嫁
* 3--夫死
*/
private int type = 0;
private String request = "";
//构造函数传递请求
public Women(int _type, String _request) {
this.type = _type;
switch (this.type) {
case 1: this.request = "女儿的请求是:" + _request; break;
case 2: this.request = "妻子的请求是:" + _request; break;
case 3: this.request = "母亲的请求是:" + _request; break;
}
}
//获得个人状况
@Override
public int getType() {
return this.type;
}
//获得个人请示
@Override
public String getRequest() {
return this.request;
}
}
(2)Handler接口及其实现类Father、Husband、Son
public abstract class Handler {
public final static int FATHER_LEVEL_REQUEST = 1;
public final static int HUSBAND_LEVEL_REQUEST = 2;
public final static int SON_LEVEL_REQUEST = 3;
//能处理的级别
private int level = 0;
//责任传递,下一个责任人
private Handler nextHandler;
//每个类都说明一下自己能处理哪些请求
public Handler(int _level) {
this.level = _level;
}
//一个女性要求逛街,你要处理这个请求
public final void HandleMessage(IWomen women) {
if (women.getType() == this.level) {
this.response(women);
} else {
if (this.nextHandler != null) {
this.nextHandler.HandleMessage(women);
} else {
System.out.println("-----没地方请示了,按不同意处理-----\n");
}
}
}
/*如果不属于你处理的请求,应该让她找下一个环节的人。
*如女儿出嫁了,还向父亲请示,父亲告诉他,应该找丈夫请示。
*/
public void setNext(Handler _handler) {
this.nextHandler = _handler;
}
//对请示的回应
protected abstract void response(IWomen women);
}
在这里也用到模板方法模式,在模板方法中判断请求的级别和当前能够处理的级别,如果相同则调用基本方法,做出反馈;如果不相等,则传递到下一个环节,由下一环节做出回应,如果已经达到环节结尾,则直接做不同意处理。
import com.sfq.impl.Handler;
import com.sfq.impl.IWomen;
public class Father extends Handler {
public Father() {
super(Handler.FATHER_LEVEL_REQUEST);
}
@Override
protected void response(IWomen women) {
System.out.println("-----女儿向父亲请示-----");
System.out.println(women.getRequest());
System.out.println("父亲的回答是:同意\n");
}
}
import com.sfq.impl.Handler;
import com.sfq.impl.IWomen;
public class Husband extends Handler {
public Husband() {
super(Handler.HUSBAND_LEVEL_REQUEST);
}
@Override
protected void response(IWomen women) {
System.out.println("-----妻子向丈夫请示-----");
System.out.println(women.getRequest());
System.out.println("丈夫的回答是:同意\n");
}
}
import com.sfq.impl.Handler;
import com.sfq.impl.IWomen;
public class Son extends Handler {
public Son() {
super(Handler.SON_LEVEL_REQUEST);
}
@Override
protected void response(IWomen women) {
System.out.println("-----母亲向儿子请示-----");
System.out.println(women.getRequest());
System.out.println("儿子的回答是:同意\n");
}
}
(3)场景类实现
import java.util.ArrayList;
import java.util.Random;
import com.sfq.action.Father;
import com.sfq.action.Husband;
import com.sfq.action.Son;
import com.sfq.action.Women;
import com.sfq.impl.Handler;
import com.sfq.impl.IWomen;
public class Client {
public static void main(String[] args) {
// 随机挑选2个女性
Random random = new Random();
ArrayList<IWomen> arrayList = new ArrayList();
for (int i = 0; i < 2; i++) {
arrayList.add(new Women(random.nextInt(4), "我要出去逛街"));
}
//定义三个请示对象
Handler father = new Father();
Handler husband = new Husband();
Handler son = new Son();
//设置请示顺序
father.setNext(husband);
husband.setNext(son);
for(IWomen women:arrayList) {
father.HandleMessage(women);
}
}
}
结果
-----母亲向儿子请示-----
母亲的请求是:我要出去逛街
儿子的回答是:同意
-----女儿向父亲请示-----
女儿的请求是:我要出去逛街
父亲的回答是:同意