行为型 - 责任链模式(Chain)
大约 3 分钟
责任链(Chain)
提示
责任链(Chain of Responsibility)模式的定义:为了避免请求发送者与多个请求处理者耦合在一起,于是将所有请求的处理者通过前一对象记住其下一个对象的引用而连成一条链;当有请求发生时,可将请求沿着这条链传递,直到有对象处理它为止
在责任链模式中,客户只需要将请求发送到责任链上即可,无须关心请求的处理细节和请求的传递过程,请求会自动进行传递。所以责任链将请求的发送者和请求的处理者解耦了
责任链 - 优缺点
责任链模式是一种对象行为型模式,其主要优点如下
降低耦合度。它将请求的发送者和接收者解耦
简化了对象。使得对象不需要知道链的结构
增强给对象指派职责的灵活性。通过改变链内的成员或者调动它们的次序,允许动态地新增或者删除责任
增加新的请求处理类很方便
主要缺点如下
不能保证请求一定被接收
系统性能将受到一定影响,而且在进行代码调试时不太方便,可能会造成循环调用
可能不容易观察运行时的特征,有碍于除错
责任链模式的结构与实现
责任链模式的结构
- 抽象处理者(Handler)角色:定义一个处理请求的接口,包含抽象处理方法和一个后继连接。
- 具体处理者(Concrete Handler)角色:实现抽象处理者的处理方法,判断能否处理本次请求,如果可以处理请求则处理,否则将该请求转给它的后继者。
- 客户类(Client)角色:创建处理链,并向链头的具体处理者对象提交请求,它不关心处理细节和请求的传递过程。
代码实现
开发一个流程流转控制器功能,通过配置是否需要自动流转到下一个流程
定义抽象的handler接口
/**
* 自动执行器抽象类
*/
public abstract class AbstractAutoHandler<S, T> {
// 下一个执行器
protected AbstractAutoHandler handler;
public void execute(S s) {
// 判断是否需要自动执行
if (isAutoExec()) {
T t = doExecute(s);
//执行下一个自动执行器
if (handler != null) {
handler.execute(t);
}
}
}
/**
* 业务逻辑实现
*/
public abstract T doExecute(S s);
/**
* 是否自动执行
*/
public abstract boolean isAutoExec();
}
定义具体实现事项
/**
* 审核自动执行器
*/
public class ApproveHandler extends AbstractAutoHandler<List<Long>, List<Long>> {
public ApproveHandler(@Autowired @Qualifier("geneHandler") AbstractAutoHandler handler) {
this.handler = handler;
}
@Override
public List<Long> doExecute(List<Long> list) {
// 业务实现...
}
@Override
public boolean isAutoExec() {
// 业务实现...
}
}
/**
* 单据生成自动执行器
*/
public class GeneHandler extends AbstractAutoHandler<List<Long>, List<Long>> {
public GeneHandler(@Autowired @Qualifier("confirmHandler") AbstractAutoHandler handler) {
this.handler = handler;
}
@Override
public List<Long> doExecute(List<Long> list) {
// 业务实现...
}
@Override
public boolean isAutoExec() {
// 业务实现...
}
}
/**
* 自动确认执行器
*/
public class ConfirmHandler extends AbstractAutoHandler<List<Long>, List<Long>> {
public ConfirmHandler() {
}
@Override
public List<Long> doExecute(List<Long> list) {
// 业务实现...
}
@Override
public boolean isAutoExec() {
// 业务实现...
}
}
注意:需要在每个具体handler里面执行下一个需要执行的handler,直到最后一个
可以看到我们在构造器中定义的关系强耦合,如果现在我们需要改变顺序或者是新增其他handler,需要改动代码,可扩展性较差
那么我们可以把 beanId 关系维护到数据库中,利用 spring 容器,根据 beanId 获取到每个具体的实例对象
这里就不多演示,有兴趣的可以自己尝试一下