设计模式:责任链、观察者模式在Spring下的应用
模式说明
责任链模式: 本本上的定义,责任链模式避免了请求发送者与接收者耦合在一起,让多个对象都有可能接收请求,将这些对象连接成一条链,并且沿着这条链传递请求,直到有对象处理它为止。
使用场景
如拦截器、过滤器也是应用责任链模式,通常即是让每个过滤器都有机会处理,都过一道。
Spring下应用技巧
-
由于链上的每个责任对象,都是同类或者实现了同一个接口。Spring中实践可以利用容器,即通过这个接口拿到其下所有的责任bean。
利用Spring这种特性,不需要客户端自己再把每个bean组合。
-
利用Spring中Order注解,可以让链上的责任bean对象做到有序。
demo
以下使用过滤器的demo来说明,观察者模式同样道理。
客户端
这里利用Spring容器机制,直接能拿到该接口下所有bean,并且可以做到指定顺序。
@Autowired
private List<IBillGenFilter> filterChain;
// 过滤器执行 利用异常机制跳出责任链
boolean filterInventory(BillContext billContext) {
try {
filterChain.forEach(filter -> filter.doFilter(context));
} catch (RuntimeException exception) {
if (exception.getCode() == ExceptionEnum.FILTER_BREAK.getCode()) {
log.info(exception.getMessage());
return false;
}
throw exception;
}
return true;
}
接口
public interface IFilter {
// 让各个bean保持无状态,context来持有各业务参数
void doFilter(Context context);
}
抽象类
让抽象类来实现该接口,抽象类中可以使用模板方法模式。
其中doFilter() 是实现IFilter接口的方法,也是个final的模板方法,设置了几个步骤,包括:
-
是否应用该过滤器对象
默认使用,留给子类具体过滤器覆盖该方法决定是否应用
-
过滤器执行前的动作
默认不作为,留给子类覆盖该方法。比如涉及到对Context业务参数做设置等
-
过滤动作
作为抽象方法留给子类具体过滤器实现
-
过滤后的检查
每个过滤器过滤后,来检查是否终止退出链,这里用异常机制实现,直接终止。调用处做异常判断,留了一些线索,如具体错误码和导致终止的过滤器。
public abstract class AbstractFilter implements IFilter {
@Override
public final void doFilter(Context context) {
// 是否应用该过滤器
if (!isValid()) {
return;
}
// 每个过滤器前置动作
setContext(context);
// 过滤动作
filter(context);
// 检查是否退出链, 利用异常控制
checkAndBreak(context);
}
/**
* 每个过滤器具体过滤实现
* @param context
*/
public abstract void filter(Context context);
protected void setContext(Context context) {
}
/**
* xx为空则终止责任链
* 终止信息记录具体过滤器
* @param context
*/
private void checkAndBreak(Context context) {
if (CollectionUtils.isNotEmpty(context.getXxx())) {
return;
}
throw new RuntimeException(ExceptionEnum.FILTER_BREAK,
String.format("fromFilter:%s", this.getClass().getSimpleName()));
}
/**
* 该过滤器是否生效
* 子类决定是否应用,默认都应用
* @return
*/
protected boolean isValid() {
return true;
}
}
具体过滤A
如果业务上需要指定过滤器的顺序,可以利用Order(),第一个过滤器可以这样写 @Order(Integer.MIN_VALUE)
这里的filter()方法是直接做了filter动作。当然也可以返回Predicate对象,然后在父类模板中做过滤动作。
@Service
@Order(Integer.MIN_VALUE)
public class AFilter extends AbstractFilter {
@Override
public void filter(Context context) {
List<Xxx> xxx = context.getXxx();
// 过滤
xxx.removeIf(x -> !MathUtils2.nonNullAndGtZero(x.getAvailQuantity()));
}
@Override
protected void setContext(Context context) {
context.setXx(xx);
}
}
具体过滤B
@Service
@Order(100)
public class BFilter extends AbstractFilter {
@Override
public void filter(Context context) {
List<Xxx> xxx = context.getXxx();
// 过滤
xxx.removeIf(x -> !MathUtils2.nonNullAndGtZero(x.getAvailQuantity()));
}
@Override
protected boolean isValid() {
return false;
}
}