面试题答案
一键面试设计要点
- 节点关系管理:
- 在构建责任链时,确保每个处理节点明确知道其下一个处理节点是谁,并且在设置下一个节点时进行严格的校验,避免误设置导致循环引用。例如,可以在
Handler
类中设置一个方法setNext(Handler next)
,在该方法中添加逻辑判断,防止将当前节点或已经在链中的节点设置为下一个节点。
- 在构建责任链时,确保每个处理节点明确知道其下一个处理节点是谁,并且在设置下一个节点时进行严格的校验,避免误设置导致循环引用。例如,可以在
- 初始化顺序:
- 按照一定的顺序初始化责任链节点,并且在初始化过程中检查是否存在循环引用。可以采用拓扑排序的思想,对于复杂的责任链结构(如树形责任链等),在构建完成后进行一次检查,确保不存在循环依赖。
- 节点标识:
- 为每个处理节点添加唯一标识。在设置下一个节点时,通过标识来判断是否存在循环引用。例如,给每个
Handler
类添加一个id
属性,在setNext
方法中通过比较id
来避免循环设置。
- 为每个处理节点添加唯一标识。在设置下一个节点时,通过标识来判断是否存在循环引用。例如,给每个
代码实现方式
abstract class Handler {
private Handler next;
private int id;
public Handler(int id) {
this.id = id;
}
public void setNext(Handler next) {
if (next == this) {
throw new IllegalArgumentException("不能将自身设置为下一个处理节点");
}
Handler current = next;
while (current != null) {
if (current.id == this.id) {
throw new IllegalArgumentException("设置下一个处理节点会导致循环引用");
}
current = current.next;
}
this.next = next;
}
public final void handleRequest(Request request) {
if (canHandle(request)) {
handle(request);
} else if (next != null) {
next.handleRequest(request);
}
}
protected abstract boolean canHandle(Request request);
protected abstract void handle(Request request);
}
class ConcreteHandler1 extends Handler {
public ConcreteHandler1(int id) {
super(id);
}
@Override
protected boolean canHandle(Request request) {
// 判断是否能处理请求
return request.getType() == 1;
}
@Override
protected void handle(Request request) {
System.out.println("ConcreteHandler1 处理请求");
}
}
class ConcreteHandler2 extends Handler {
public ConcreteHandler2(int id) {
super(id);
}
@Override
protected boolean canHandle(Request request) {
// 判断是否能处理请求
return request.getType() == 2;
}
@Override
protected void handle(Request request) {
System.out.println("ConcreteHandler2 处理请求");
}
}
class Request {
private int type;
public Request(int type) {
this.type = type;
}
public int getType() {
return type;
}
}
在上述代码中,Handler
类通过setNext
方法检查是否会导致循环引用。每个具体的处理类(如ConcreteHandler1
和ConcreteHandler2
)继承自Handler
类,实现具体的请求处理逻辑。Request
类表示请求对象。在使用时,按顺序构建责任链并传递请求:
public class Main {
public static void main(String[] args) {
Handler handler1 = new ConcreteHandler1(1);
Handler handler2 = new ConcreteHandler2(2);
handler1.setNext(handler2);
Request request = new Request(1);
handler1.handleRequest(request);
}
}
通过上述设计和代码实现,可以有效避免责任链模式中处理节点之间的循环引用问题。