1.定义
顾名思义,责任链模式(Chain of Responsibility Pattern)为请求创建了一个接收者对象的链。这种模式给予请求的类型,对请求的发送者和接收者进行解耦。这种类型的设计模式属于行为型模式。
在这种模式中,通常每个接收者都包含对另一个接收者的引用。如果一个对象不能处理该请求,那么它会把相同的请求传给下一个接收者,依此类推。
简单来说:责任链模式就是使多个对象都有机会处理请求,从而避免请求的发送者和接受者之间的耦合关系,将这些对象连成一条链,并沿着这条链传递请求,直到有一个对象处理它为止!
2.概述
在设计Java程序时,可能需要设计很多对象来满足用户的请求。比如,要建立一个古瓷器鉴定系统,一个好的设计方案就是将古瓷器分门别类,然后创建若干对象,每个对象处理一类古瓷器的鉴定。为了能更好地组织这些负责鉴定古瓷器的对象,可以将这些对象组成一个责任链。当用户需要鉴定古瓷器的时候,系统可以让责任链上的第一个对象来处理用户的请求,这个对象首先检查自己是否能够处理用户请求,如果能处理就反馈有关处理结果,如果无法处理就将用户的请求传递给责任链上的下一个对象,一次类推,直到责任链上的某个对象能处理用户的请求,如果责任链上的末端都无法处理用户的请求,那么用户的本次请求就无任何结果。
责任链模式就是使用多个对象处理用户的请求的成熟模式,责任链模式的关键就是将用户的请求分派给许多对象,这些对象被组织成一个责任链,即每一个对象含有后继对象的引用,并要求责任链上的每个对象,如果能处理用户的请求,就做出请求,不在将用户的请求传递给责任链上的下一个对象;如果不能处理用户胡的请求,就必须将用户的请求传递给责任链上的下一个对象。
3.应用场景
1、有多个对象可以处理同一个请求,具体哪个对象处理该请求由运行时刻自动确定。
2、在不明确指定接收者的情况下,向多个对象中的一个提交一个请求。
3、可动态指定一组对象处理请求。
4.模式的结构和使用
责任链模式的结构中主要包括两种角色
1.处理者(Handler):处理者是一个接口,负责规定具体的处理者处理用户请求的方法以及具体处理者设置后继对象的方法;
2.具体处理者(ConcreteHandler):具体处理者是实现处理者接口的类的实例。具体的处理者通过调用处理者接口规定的方法处理用户的请求,即在接到用户的请求后,处理者将调用接口规定的方法,在执行该方法的过程中,如果发现能处理用户的请求,就处理有关数据,否则就反馈无法处理的信息给用户,然后将该用户的请求传递给自己的后继对象。
1.责任链模式的UML类图
handlerRequest()方法是当前的具体处理者处理当前的请求,setNextHandler()方法是指向下一个处理对象的方法。
2.结构的描述
以下通过一个简单的问题来描述责任链模式中所涉及的各个角色。
用户通过提交一个人的身份证号码,想知道该人是否在北京,上海或天津居住。
针对上述问题,使用责任链模式设计一个简单的系统来处理用户的请求。
1.处理者(Handler)
本问题中,处理者(Handler)接口定义了处理请求的方法以及形成责任链的方法。
package com.xing.duty;
public interface Handler {
//处理当前请求
public abstract void handlerRequest(String number);
//指向下一个处理者 以便于形成一条责任处理链
public abstract void setNextHandler(Handler handler);
}
2.具体处理者
对于本问题 ,一共有三个负责创建具体处理者的类,分别是Beijing,Shanghai和Tianjing,三个类的代码如下所示:
在beijing具体处理类中,模拟定义了一组数据,如果传入的数据在numberList集合中,则表示已经知道该人已经在北京居住,则不需要按照责任链往后继续传递,直接输入即可,如果传入的数据不在当前的numberList集合中,如果链上的下一处理者不为空,则继续向后传递处理。
Beijing.java
package com.xing.duty;
import java.util.ArrayList;
public class Beijing implements Handler{
private Handler handler;
private ArrayList<String> numberList;
public Beijing() {
numberList=new ArrayList<>();
numberList.add("111");//这里使用模拟的身份证号码
numberList.add("222");
numberList.add("333");
}
@Override
public void handlerRequest(String number) {
if(numberList.contains(number)){
System.out.println("该人在北京居住");
}else{
System.out.println("该人不在北京居住");
if(handler!=null){
handler.handlerRequest(number);//将请求传递给下一个处理者
}
}
}
@Override
public void setNextHandler(Handler handler) {
this.handler=handler;
}
}
Shanghai.java
package com.xing.duty;
import java.util.ArrayList;
public class Shanghai implements Handler{
private Handler handler;
private ArrayList<String> numberList;
public Shanghai() {
numberList=new ArrayList<>();
numberList.add("444");//这里使用模拟的身份证号码
numberList.add("555");
numberList.add("666");
}
@Override
public void handlerRequest(String number) {
if(numberList.contains(number)){
System.out.println("该人在上海居住");
}else{
System.out.println("该人不在上海居住");
if(handler!=null){
handler.handlerRequest(number);//将请求传递给下一个处理者
}
}
}
@Override
public void setNextHandler(Handler handler) {
this.handler=handler;
}
}
Tianjin.java
package com.xing.duty;
import java.util.ArrayList;
public class Tianjin implements Handler{
private Handler handler;
private ArrayList<String> numberList;
public Tianjin() {
numberList=new ArrayList<>();
numberList.add("777");//这里使用模拟的身份证号码
numberList.add("888");
numberList.add("999");
}
@Override
public void handlerRequest(String number) {
if(numberList.contains(number)){
System.out.println("该人在天津居住");
}else{
System.out.println("该人不在天津居住");
if(handler!=null){
handler.handlerRequest(number);//将请求传递给下一个处理者
}
}
}
@Override
public void setNextHandler(Handler handler) {
this.handler=handler;
}
}
3.主程序测试
在主程序里面,主要定义了形成责任链的方法,以及通过责任链判断当前用户居住的地方。
Application.java
package com.xing.duty;
public class Application {
private Handler beijing,shanghai,tianjin;//定义责任链上的对象
//建立责任链
public void createChain(){
beijing=new Beijing();
shanghai=new Shanghai();
tianjin=new Tianjin();
//创建责任链
beijing.setNextHandler(shanghai);
shanghai.setNextHandler(tianjin);
}
public void responseClient(String number){
beijing.handlerRequest(number);
}
public static void main(String[] args) {
Application application = new Application();
application.createChain();
//判断身份证号码为555的人居住在哪里?
application.responseClient("555");
}
}
4.测试结果展示
5.责任链模式的优点
1、降低耦合度。它将请求的发送者和接收者解耦。
2、简化了对象。使得对象不需要知道链的结构。
3、增强给对象指派职责的灵活性。通过改变链内的成员或者调动它们的次序,允许动态地新增或者删除责任。
4、增加新的请求处理类很方便。