什么是责任链模式?什么时候用?
-
一个请求,多个对象都可以处理,这些对象组合成一条链,沿着这条链传递请求,直到有对象处理它。这样做,避免了请求的发送者和接收者的耦合。
-
应用场景:Android中的View树,触摸事件的传递。back返回键、各种按键事件的传递。Activity的生命周期派发给Fragment\Fragment事件派发给子Fragment。
怎么实现责任链模式?
-
首先定义一个处理者接口,所有处理者都需要实现该接口。
-
定义一个Chain链对象,提供增加、移除处理者方法,内部集合存储处理者(处理者接口),外部调用处理方法时,遍历处理者集合,调用遍历到的处理者对象的处理方法,如果有返回值,则代表有对象处理,返回处理后的结果。
责任链模式优雅处理图片Url请求添加Token验证
上一篇策略模式博客中,我们使用策略模式打造了一个可替换Glide、Fresco实现的ImageLoader。但有些项目,请求图片Url需要在请求的header里面带一个token验证才能请求。
我们知道Glide有GlideUrl,可以组装url和header,所以最简单的方法:外部传入url的时候重载一个GlideUrl的方法,传进来加载就好了。但是这时候我们应该思考一下,Url类型的请求媒体是Url,如果是文件或者流再或者是其他类型呢?也要加一些验证或附加项,那么重载方法就会很多。那么责任链模式就比较适合了。
- 思路:
- 外部依旧传入原始的Url。
- 建立请求对象ImageRequest,包裹url和header参数。
- 建立filter过滤器接口,每个过滤器对象都要实现,做相应的处理。
- 建立Chain链对象,提供添加、移除过滤器方法,提供process处理方法,遍历过滤器,最后将处理结果交给ImageLoader
- ImageLoader收到结果后,转交给设置的策略ILoaderStrategy接口实现类处理,例如Glide的实现类GlideLoader,将ImageRequest中的参数构造GlideUrl进行设置。
- 建立请求对象,作为
public class ImageRequest {
/**
* 请求加载资源
*/
private Object source;
/**
* 请求头
*/
private Map<String, String> headers;
public ImageRequest(Object source, Map<String, String> headers) {
this.source = source;
this.headers = headers;
}
//...省略set、get方法
}
- 建立过滤器接口IFilter
public interface IFilter {
/**
* 返回当前过滤器的优先级,值越小越优先
*/
int getPriority();
/**
* 是否可以处理,返回true代表可以处理,false为不可处理
*/
boolean isCanHandle(ImageRequest request);
/**
* 准备过滤的回调,需要返回过滤后的请求,包括Url和Headers请求头
*/
ImageRequest doFilter(ImageRequest request);
}
- 建立添加Token的过滤器
public class GlobalImageFilter implements IFilter {
@Override
public int getPriority() {
return 1;
}
@Override
public boolean isCanHandle(ImageRequest request) {
//只处理Url是String,并且是http\https的情况
Object source = request.getSource();
boolean isCanHandle = false;
if (source instanceof String) {
String url = (String) source;
if (url.startsWith("http") || url.startsWith("https")) {
isCanHandle = true;
}
}
return isCanHandle;
}
@Override
public ImageRequest doFilter(ImageRequest request) {
//这里添加Token到Header的Map中。
Map<String, String> headers = request.getHeaders();
headers.put(ApiConstant.Api.IMAGE_TOKEN, EncryptionUtil.getEncrytionStr());
return request;
}
}
- 建立Chain链对象
public class FilterChain {
private ArrayList<IFilter> mFilters = new ArrayList<>();
public void addFilter(IFilter filter) {
mFilters.add(filter);
}
public void removeFilter(IFilter filter) {
mFilters.remove(filter);
}
/**
* 处理方法
*/
public ImageRequest process(ImageRequest request) {
//没有设置,直接返回
if (mFilters.isEmpty()) {
return request;
}
//只有一个,不用遍历
if (mFilters.size() == 1) {
IFilter filter = mFilters.get(0);
if (filter.isCanHandle(request)) {
return mFilters.get(0).doFilter(request);
}
}
//先按优先级排序,从小到大排序
Collections.sort(mFilters, new Comparator<IFilter>() {
@Override
public int compare(IFilter o1, IFilter o2) {
return Integer.compare(o1.getPriority(), o2.getPriority());
}
});
//多个执行遍历,每次遍历都将结果保存,下次遍历就将上一个过滤器处理的结果传入
for (IFilter filter : mFilters) {
if (filter.isCanHandle(request)) {
request = filter.doFilter(request);
}
}
return request;
}
}
- ImageLoader中添加FilterChain实例。提供添加、移除过滤器的方法。
public class ImageLoader {
private ILoaderStrategy mLoader;
private Context mContext;
//过滤器链
private FilterChain mChain = new FilterChain();
public ImageLoader with(Context context) {
mContext = context;
return this;
}
//...省略一些方法
public FilterChain getFilterChain() {
return mChain;
}
public ImageLoader addFilter(IFilter filter) {
mChain.addFilter(filter);
return this;
}
public ImageLoader removeFilter(IFilter filter) {
mChain.removeFilter(filter);
return this;
}
}
- 注册过滤器
ImageLoader.with(this)
.setLoader(new GlideLoader())
//增加一个Url的过滤器来添加验证Header
.addFilter(new GlobalImageFilter());
- 最后,策略实现类,load方法,调用ImageLoader. getFilterChain().process(内部转调FilterChain的process()进行责任链处理)
public class GlideLoader implements ILoaderStrategy {
//...省略一些方法
@Override
public void load(@NotNull Context context, @NotNull LoadOption option, @NotNull ImageView targetView) {
//1、根据option中的资源类型决定加载的资源类型
Object typeValue = option.getDrawableType().getTypeValue();
ImageRequest request = ImageLoader. getFilterChain().process(new ImageRequest(typeValue, new HashMap()));
Object loadType = typeValue;
if(request.getSource instanceof String) {
loadType = new GlideUrl(request.getSource(),
}
request.getHeaders());
//2、变换、裁剪操作
//3、加载
Glide.with(context).load(loadType).into(targetView);
}
}
总结
-
责任链将处理过程分散到具体的处理者实现中,降低了处理和调用方的耦合。
-
设计模式的通病,会增加子类的个数。
网友评论