责任链模式

发布时间 2023-03-30 22:04:17作者: FatalFlower

概述

《设计模式》一书中对于 “责任链模式” 的意图描述如下:

使多个对象有机会处理请求,从而避免请求的发送者和接受者之间的耦合关系。将这些对象连成一条链,并沿着这条链传递请求,直到有一个对象处理它为止

一般的 UML 结构图如下所示:

reposibility_pattern_uml.png

其中,Handler 将会包含直接后继处理类 successor,用于处理后续的更通用请求

一般在以下情况下使用责任链模式:

  • 有多个对象可以处理一个请求,哪个对象处理请求由运行时进行确定
  • 在不想明确指定接受者的情况下,向多个对象中的一个提交一个请求
  • 可处理请求的对象集合应该被动态指定

具体示例

在某些情况下,可能需要对相关的请求参数进行相关的解析,得到在某个通用模块中需要用到的参数,然而,对于不同的请求参数,解析的方式也可能不同,因此我们可以通过使用责任链模式来解决这个问题。

假设我们现在的系统中存在以下的参数类型:

public interface UpdateParam { // 更新数据时的参数类型
    String updatedId();
}

public interface DeletedParam { // 删除数据时的参数类型
    String deletedId();
}

public interface InsertedParam { // 增加数据时的参数类型
    String insertedId();
}

在当前的上下文环境下,这三个接口返回的都是通用模块需要的参数,但是由于这三个参数的使用具体由不同的开发使用,现在已经很难对这几个参数类型进行 “提炼父类” 的重构。并且除了这三个参数类型之外,可能系统中还存在某些其它类型的参数,如 ListMap 等,对这些类型同样无法使用 “提炼父类” 的操作进行泛化处理。为了能够适配通用模块的需求,我们可以定义如下的处理类 Handler

public abstract class AbstractParamHandler {
    private final AbstractParamHandler successor;
    
    public AbstractParamHandler(AbstractParamHandler successor) {
        this.successor = successor;
    }
    
    protected String successorHandler(Object Param) {
        return this.successor == null ? null : this.successor.handler(param);
    }
    
    // 针对参数对象,对其进行解析以得到对应的通用参数值,如果无法解析,则返回 null
    public abstract String handler(Object param);
}

针对上面我们提到的三种参数类型,我们可以定义对应的参数处理类:

public class InsertedParamHandler extends AbstractParamHandler {
    
    public InsertedParamHandler(AbstractParamHandler successor) {
        super(successor);
    }
    
    @Override
    public String handler(Object param) {
        if (!(param instanceof InsertedParam)) {
             return successorHandler(param);
        }
        return ((InsertedParam) param).insertedId();
    }
}

public class UpdatedParamHandler extends AbstractParamHandler {
    public UpdatedParamHandler(AbstractParamHandler successor) {
        super(successor);
    }
    
    @Override
    public String handler(Object param) {
        if (!(param instanceof UpdatedParam)) {
            return successorHandler(param);
        }
        return ((UpdatedParam) param).updatedId();
    }
}

public class DeletedParamHandler extends AbstractParamHandler {
    public DeletedParamHandler(AbstractParamHandler successor) {
        super(successor);
    }
    
    @Override
    public String handler(Object param) {
        if (!(param instanceof DeletedParam)) {
            return successorHandler(param);
        }
        return ((DeletedParam) param).deletedId();
    }
}

对于客户端来讲,只要适当组织好这些处理类之间的关系即可:

public class Client {
    private AbstractParamHandler handler;
    public Client() {
        // 将这三个处理类组合成处理链
        InsertParamHandler h1 = new InsertParamHandler(null);
        UpdatedParamHandler h2 = new UpdatedParamHandler(h1);
        DeleteParamHandler h3 = new DeletedParamHandler(h2);
        this.handler = h3;
    }
    
    String handler(Object param) {
        return handler.handler(param);
    }
}

如果后续发现 List 类型的参数也需要解析,那么只需要再将 DeletedParamHandler 作为它的后继处理即可完成对所有类型的参数解析

总结

针对不同请求的特殊处理,通过责任连模式来选择合适的处理对象,一般这种模式会结合 “组合模式” 一起使用,可以合理的适配每个父组件的特殊处理



参考:

[1] 《设计模式—可复用面向对象基础》