概念:
职责链模式是一种行为设计模式,它允许将请求沿着处理者链进行传递,直到有一个处理者能够处理该请求为止。每个处理者都可以选择将请求传递给下一个处理者或自行处理。
特点:
- 解耦发送者和接收者:发送者不需要知道具体的接收者,只需将请求发送给第一个处理者即可。
- 动态组合:可以根据需要动态地组合和调整职责链中的各个节点。
- 灵活性:可以灵活地添加、修改或删除职责链上的节点。
优点:
- 提高代码复用性:每个节点都只关心自己负责的部分,易于扩展和维护。
- 易于扩展新功能:通过增加新的节点来扩展功能而无需修改现有代码。
- 可以动态改变顺序和条件:可以根据实际情况动态调整节点之间的顺序或添加条件判断。
缺点:
- 请求可能无法被正确处理:如果没有合适的节点能够处理某个请求,则该请求可能会被忽略。
- 性能开销较大:由于需要遍历整个职责链来找到合适的处理器,因此在大型职责链中可能会影响性能。
适用场景:
- 有多个对象可以处理同一请求,但具体的处理者在运行时才能确定。
- 需要动态地指定可处理请求的对象集合。
- 在不明确接收者的情况下,将一个请求传递给多个对象中的一个或几个。
实现方式:
链表方式
使用链表或数组来存储职责链节点,并在每个节点中定义一个方法来处理请求。每个节点都持有下一个节点的引用
实现原理:
- 创建一个抽象的处理者类,其中包含一个指向下一处理者的引用。
- 派生具体的处理者类,并重写父类中的方法,在该方法中判断是否能够处理请求,如果可以则进行处理;否则将请求传递给下一位处理者。
- 在客户端代码中创建职责链并连接各个节点。
实现代码:
// 抽象处理者类
abstract class Handler {
protected Handler nextHandler;
public void setNextHandler(Handler handler) {
this.nextHandler = handler;
}
public abstract void handleRequest(Request request);
}
// 具体处理者类A
class ConcreteHandlerA extends Handler {
@Override
public void handleRequest(Request request) {
if (request.getType().equals("TypeA")) {
// 处理请求
System.out.println("ConcreteHandlerA处理了请求:" + request.getContent());
} else {
// 无法处理,传递给下一个处理者
if (nextHandler != null) {
nextHandler.handleRequest(request);
} else {//已经遍历完了,表示没有节点能处理了
System.out.println("无法处理该请求:" + request.getContent());
}
}
}
}
// 具体处理者类B
class ConcreteHandlerB extends Handler {
@Override
public void handleRequest(Request request) {
if (request.getType().equals("TypeB")) {
// 处理请求
System.out.println("ConcreteHandlerB处理了请求:" + request.getContent());
} else {
// 无法处理,传递给下一个处理者
if (nextHandler != null) {
nextHandler.handleRequest(request);
} else {//已经遍历完了,表示没有节点能处理了
System.out.println("无法处理该请求:" + request.getContent());
}
}
}
}
// 请求类
class Request {
private String type;
private String content;
public Request(String type, String content) {
this.type = type;
this.content = content;
}
public String getType() {
return type;
}
public String getContent() {
return content;
}
}
public class Main {
public static void main(String[] args) {
Handler handlerA = new ConcreteHandlerA();
Handler handlerB = new ConcreteHandlerB();
handlerA.setNextHandler(handlerB);
Request request1 = new Request("TypeA", "请求内容1");
handlerA.handleRequest(request1); // 输出:ConcreteHandlerA处理了请求:请求内容1
Request request2 = new Request("TypeB", "请求内容2");
handlerA.handleRequest(request2); // 输出:ConcreteHandlerB处理了请求:请求内容2
Request request3 = new Request("TypeC", "请求内容3");
handlerA.handleRequest(request3); // 输出:无法处理该请求
}
}
在上述示例中,我们创建了两个具体的处理者类`ConcreteHandlerA`和`ConcreteHandlerB`,它们分别能够处理类型为"TypeA"和"TypeB"的请求。如果无法处理某个类型的请求,则将其传递给下一个处理者。
客户端代码中创建了职责链,并将具体的处理者按照顺序连接起来。然后通过调用第一个节点(即`handlerA`)的`handleRequest()`方法来触发整个职责链的执行。在实际应用中,可以根据实际需求进行扩展和修改,例如添加新的具体处理者类或修改判断条件等。
递归调用
使用递归调用,在每个节点中判断是否需要继续传递请求给下一个节点
实现原理
使用递归调用可以实现请求沿着职责链依次传递的功能。当一个处理者无法处理请求时,它会将请求传递给下一个处理者,并继续调用下一个处理者的处理方法,直到找到能够处理该请求的处理者为止。
实现代码
abstract class Handler {
private Handler nextHandler;
public void setNextHandler(Handler nextHandler) {
this.nextHandler = nextHandler;
}
public void handleRequest(Request request) {
if (canHandle(request)) {
processRequest(request);
} else if (nextHandler != null) {
nextHandler.handleRequest(request);
} else {
System.out.println("无法处理该请求");
}
}
protected abstract boolean canHandle(Request request);
protected abstract void processRequest(Request request);
}
class ConcreteHandlerA extends Handler {
@Override
protected boolean canHandle(Request request) {
return "TypeA".equals(request.getType());
}
@Override
protected void processRequest(Request request) {
System.out.println("ConcreteHandlerA处理了请求:" + request.getContent());
// 具体处理逻辑...
}
}
class ConcreteHandlerB extends Handler {
@Override
protected boolean canHandle(Request request) {
return "TypeB".equals(request.getType());
}
@Override
protected void processRequest(Request request) {
System.out.println("ConcreteHandlerB处理了请求:" + request.getContent());
// 具体处理逻辑...
}
}
class Request {
private String type;
private String content;
public Request(String type, String content) {
this.type = type;
this.content = content;
}
public String getType() {
return type;
}
public String getContent() {
return content;
}
}
public class Main {
public static void main(String[] args) {
Handler handlerA = new ConcreteHandlerA();
Handler handlerB = new ConcreteHandlerB();
handlerA.setNextHandler(handlerB);
Request request1 = new Request("TypeA", "请求内容1");
handlerA.handleRequest(request1); // 输出:ConcreteHandlerA处理了请求:请求内容1
Request request2 = new Request("TypeB", "请求内容2");
handlerA.handleRequest(request2); // 输出:ConcreteHandlerB处理了请求:请求内容2
Request request3 = new Request("TypeC", "请求内容3");
handlerA.handleRequest(request3); // 输出:无法处理该请求
}
}
在上述示例中,我们创建了一个抽象处理者类Handler,实现了一个递归调用的处理方法,如果无法处理某个类型的请求,则将其递归传递给下一个处理者。然后创建了两个具体的处理者类ConcreteHandlerA
和ConcreteHandlerB
,它们分别能够处理类型为"TypeA"和"TypeB"的请求。
客户端代码中创建了职责链,并将具体的处理者按照顺序连接起来。然后通过调用第一个节点(即handlerA
)的handleRequest()
方法来触发整个职责链的执行。
在使用递归调用实现职责链模式时需要注意以下问题:
- 无限循环:如果职责链中存在循环引用或某个节点错误地将请求再次发送给自己,则可能导致无限循环。为了避免这种情况发生,我们需要在代码中添加合适的条件来控制结束递归。
- 性能影响:由于每个节点都会进行递归调用,可能导致性能方面的影响。特别是当职责链较长且层级较深时,可能会增加系统开销和延迟。
注解方式
使用注解方式来动态生成职责链,提高灵活性和可配置性。
实现原理及代码
首先,我们需要定义一个抽象处理者类Handler
,它包含了设置下一个处理者的方法和处理请求的抽象方法。具体的处理者类将继承该抽象类并实现自己的业务逻辑。
创建Handle.java
public abstract class Handler {
private Handler nextHandler;
public void setNextHandler(Handler nextHandler) {
this.nextHandler = nextHandler;
}
public void handleRequest(Request request) {
if (canHandle(request)) {
process(request);
} else if (nextHandler != null) {
nextHandler.handleRequest(request);
} else {
System.out.println("无法护理该请求.");
}
}
protected abstract boolean canHandle(Request request);
protected abstract void process(Request request);
}
接下来,我们创建两个具体的处理者类ConcreteHandlerA
和ConcreteHanderB
。这里假设它们分别能够处理类型为"TypeA"和"TypeB"的请求。
创建HandlerAnnotation.java
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface HandlerAnnotation {
String type();
}
创建ConcreteHanlderA.java
@HandlerAnnotation(type = "TypeA")
public class ConcreteHanlderA extends Handler {
@Override
protected boolean canHandle(Request request) {
return "TypeA".equals(request.getType());
}
@Override
protected void process(Request request) {
// 处理 TypeA 类型请求的逻辑
System.out.println("ConcreteHandlerA 处理了请求");
}
}
创建ConcreteHanlderB.java
@HandlerAnnotation(type = "TypeB")
public class ConcreteHandlerB extends Handler {
@Override
protected boolean canHandle(Request request) {
return "TypeB".equals(request.getType());
}
@Override
protected void process(Request request) {
// 处理 TypeB 类型请求的逻辑
System.out.println("ConcreteHandlerB处理了请求");
}
}
在上述代码中,我们使用了HandlerAnnotation
注解来标识具体处理者类能够处理的请求类型。
接下来,我们创建一个简单的请求类Request
,它包含一个类型属性和相应的getter方法。
创建Request.java
public class Request {
private String type;
public Request(String type) {
this.type = type;
}
public String getType() {
return type;
}
}
最后,在客户端代码中扫描并构建职责链,并触发整个职责链的执行。
创建Main.java
import java.lang.annotation.*;
import java.util.ArrayList;
import java.util.List;
import java.io.File;
import java.io.IOException;
import java.net.URL;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.List;
public class Main {
public static void main(String[] args) {
List<Handler> handlers = new ArrayList<>();
// 扫描具体处理者类上的注解信息,并创建处理者对象
for (Class<?> clazz : getClasses()) {
Annotation annotation = clazz.getAnnotation(HandlerAnnotation.class);
if (annotation != null && Handler.class.isAssignableFrom(clazz)) {
try {
Handler handler = (Handler) clazz.getDeclaredConstructor().newInstance();
handlers.add(handler);
} catch (Exception e) {
e.printStackTrace();
}
}
}
// 按照顺序连接处理者对象形成职责链
int size = handlers.size();
for (int i = 0; i < size - 1; i++) {
handlers.get(i).setNextHandler(handlers.get(i + 1));
}
// 使用第一个节点(即handlers.get(0))来触发整个职责链的执行
Request requestA = new Request("TypeA");
handlers.get(0).handleRequest(requestA);
Request requestB = new Request("TypeB");
handlers.get(0).handleRequest(requestB);
Request requestC = new Request("TypeC");
handlers.get(0).handleRequest(requestC);
}
private static List<Class<?>> getClasses() {
// 在这里返回具体处理者类所在的包路径下的所有类,或通过其他方式获取需要扫描的具体处理者类
List<Class<?>> classes = new ArrayList<>();
String packageName = "com.example.posttest"; // 替换为具体处理者类所在的包路径
try {
ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
String path = packageName.replace('.', '/');
Enumeration<URL> resources = classLoader.getResources(path);
while (resources.hasMoreElements()) {
URL resource = resources.nextElement();
File file = new File(resource.getFile());
if (file.isDirectory()) {
for (File f : file.listFiles()) {
if (f.isFile() && f.getName().endsWith(".class")) {
String className = packageName + '.' + f.getName().substring(0, f.getName().length() - 6);
Class<?> clazz = Class.forName(className);
classes.add(clazz);
}
}
}
}
} catch (IOException | ClassNotFoundException e) {
e.printStackTrace();
}
return classes;
}
}
在上述示例中,我们为每个具体处理者类添加了HandlerAnnotation
注解,该注解标识了处理者所能处理的请求类型以及其在职责链中的位置。然后在客户端代码中扫描具体处理者类上的注解信息,并根据order值排序构建职责链。