????????“当你想要让一个以上的对象有机会能够处理某个请求的时候,就使用责任链模式。”
1 简介
????????通过责任链模式,你可以为某个请求创建一个对象链。每个对象依序检查此请求,并对其进行处理,或者将它传给链中的下一个对象。
????????链中的每个对象扮演处理器,并且有一个后继对象(successor)。如果它可以处理请求,就进行处理;否则把请求转发给后继者。
????????通过责任链模式,我们可以将一个复杂的功能拆分成多个子模块(前提是这些子模块的逻辑高度统一),每个子模块只需要专注于自己的业务逻辑,不需要关心其他的业务。而且对于不同的业务来说可以组装不同的子模块,更加灵活。
2 示例
????????Handler:
public abstract class Handler {
protected Handler successor;
public void setSuccessor(Handler successor) {
this.successor = successor;
}
protected abstract void handleRequest();
}
????????各个子实现:
public class SpamHandler extends Handler {
@Override
protected void handleRequest() {
System.out.println("垃圾邮件");
if (successor != null) {
successor.handleRequest();
}
}
}
public class FanHandler extends Handler {
@Override
protected void handleRequest() {
System.out.println("粉丝");
if (successor != null) {
successor.handleRequest();
}
}
}
public class ComplaintHandler extends Handler {
@Override
protected void handleRequest() {
System.out.println("投诉");
if (successor != null) {
successor.handleRequest();
}
}
}
public class NewLocHandler extends Handler {
@Override
protected void handleRequest() {
System.out.println("新位置");
if (successor != null) {
successor.handleRequest();
}
}
}
????????使用:
public static void main(String[] args) {
SpamHandler spamHandler = new SpamHandler();
FanHandler fanHandler = new FanHandler();
ComplaintHandler complaintHandler = new ComplaintHandler();
NewLocHandler newLocHandler = new NewLocHandler();
spamHandler.setSuccessor(fanHandler);
fanHandler.setSuccessor(complaintHandler);
complaintHandler.setSuccessor(newLocHandler);
spamHandler.handleRequest();
}
????????运行结果:
垃圾邮件
粉丝
投诉
新位置
? ? ? ? 上面的示例演示了在请求下个handler之前打印了一句话,代表当前handler的业务处理。也可以在请求下个handler之后打印一句话,甚至说可以改变调用下个handler本身的逻辑。
? ? ? ? 而在实际的应用中也有很多的框架使用到了责任链模式,比方说MyBatis的二级缓存和插件(我之前写过《较真儿学源码系列-MyBatis核心流程源码分析》,感兴趣的话可以查看):
?????????Spring AOP的通知机制?(我之前写过《较真儿学源码系列-Spring AOP核心流程源码分析》,感兴趣的话可以查看):
?????????Netty的channelHandler?(我之前写过《较真儿学源码系列-Netty核心流程源码分析》,感兴趣的话可以查看):
3 变种
? ? ? ? 上面演示的示例中,如果我们想要新增一个handler的话,不仅需要新创建一个类、写这个handler本身的逻辑。还需要在main方法中对这个handler进行包装,指定下一个handler。这样就很麻烦。如果来了新的需求的话,只创建新的handler类,不动其他逻辑的话,也是可以实现的。如下所示:
????????Handler:
public abstract class NewHandler {
protected abstract void handleRequest();
}
????????各个子实现:
@Order(1)
public class SpamNewHandler extends NewHandler {
@Override
protected void handleRequest() {
System.out.println("垃圾邮件");
}
}
@Order(2)
public class FanNewHandler extends NewHandler {
@Override
protected void handleRequest() {
System.out.println("粉丝");
}
}
@Order(3)
public class ComplaintNewHandler extends NewHandler {
@Override
protected void handleRequest() {
System.out.println("投诉");
}
}
@Order(4)
public class NewLocNewHandler extends NewHandler {
@Override
protected void handleRequest() {
System.out.println("新位置");
}
}
????????使用:
public static void main(String[] args) throws Exception {
//获取所有handler实现类
Set<HandlerClassDTO> handlerClasses = getHandlerClasses();
for (HandlerClassDTO handlerClass : handlerClasses) {
Class<? extends NewHandler> clazz = handlerClass.getClazz();
Constructor<? extends NewHandler> constructor = clazz.getConstructor();
NewHandler newHandler = constructor.newInstance();
//处理请求
newHandler.handleRequest();
}
}
private static final Set<HandlerClassDTO> HANDLER_CLASSES = Sets.newLinkedHashSetWithExpectedSize(4);
private static Set<HandlerClassDTO> getExceptionContentClasses() {
if (CollectionUtils.isNotEmpty(HANDLER_CLASSES)) {
return HANDLER_CLASSES;
}
synchronized (HANDLER_CLASSES) {
//DCL
if (CollectionUtils.isNotEmpty(HANDLER_CLASSES)) {
return HANDLER_CLASSES;
}
String packageName = NewHandler.class.getPackage().getName();
Reflections reflections = new Reflections(new ConfigurationBuilder()
.forPackages(packageName));
Set<Class<? extends NewHandler>> classes = reflections.getSubTypesOf(NewHandler.class);
Set<HandlerClassDTO> handlerClassDTOSet = classes.stream().map(item -> new HandlerClassDTO(item, getOrder(item))).collect(Collectors.toSet());
//根据@Order排序
handlerClassDTOSet = handlerClassDTOSet.stream().sorted(Comparator.comparingInt(HandlerClassDTO::getOrder)).collect(Collectors.toCollection(LinkedHashSet::new));
HANDLER_CLASSES.addAll(handlerClassDTOSet);
return handlerClassDTOSet;
}
}
private static int getOrder(Class<?> clazz) {
Order annotation = clazz.getAnnotation(Order.class);
if (annotation == null) {
return Integer.MAX_VALUE;
}
return annotation.value();
}
????????运行结果:
垃圾邮件
粉丝
投诉
新位置
? ? ? ? 这里使用了Reflections来反射获取NewHandler的所有实现类,并缓存了起来(我之前写过对Reflections的使用《Java反射工具:Reflections》,感兴趣的话可以查看)。各个Handler的执行顺序依赖于@Order注解(这里只是提供了一种实现思路,也可以有别的实现。例如,加入别的注解来对handler是否加入责任链进行区分)。
? ? ? ? 展示这个例子并不是在说这种实现方案就比第2小节的实现要更好。第2小节的实现更灵活,也更简单,这是它的优势;而上面的例子虽然能完全写活,但更复杂。也丢掉了在下一个handler执行之前和之后处理的功能,只能遍历地去一个个去处理当前handler的内容(可以去尝试解决,但肯定会更加复杂)。具体采用哪种方案需要视情况而定。
????????另外,我在这里想说的是,学习设计模式并应用的话,不要去形成一种固定思维。不要说这种设计模式规定地怎么去写,我就一定要按照这种方式去写。就拿责任链模式来说,我设计handler的时候就一定要加入一个successor的后继节点吗?不一定。其实我只要能把职责分开,再通过组合的方式,一个个去遍历执行handler的话,就可以认为是使用到了责任链模式(就如同我上面使用的那样)。
|