美文网首页设计模式
设计模式-责任链模式

设计模式-责任链模式

作者: h2coder | 来源:发表于2020-10-17 00:52 被阅读0次

什么是责任链模式?什么时候用?

  • 一个请求,多个对象都可以处理,这些对象组合成一条链,沿着这条链传递请求,直到有对象处理它。这样做,避免了请求的发送者和接收者的耦合。

  • 应用场景: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进行设置。
  1. 建立请求对象,作为
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方法
}
  1. 建立过滤器接口IFilter
public interface IFilter {
    /**
     * 返回当前过滤器的优先级,值越小越优先
     */
    int getPriority();
    
    /**
     * 是否可以处理,返回true代表可以处理,false为不可处理
     */
    boolean isCanHandle(ImageRequest request);

    /**
     * 准备过滤的回调,需要返回过滤后的请求,包括Url和Headers请求头
     */
    ImageRequest doFilter(ImageRequest request);
}
  1. 建立添加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;
    }
}
  1. 建立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;
    }
}
  1. 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;
    }
}
  1. 注册过滤器
ImageLoader.with(this)
.setLoader(new GlideLoader())
//增加一个Url的过滤器来添加验证Header
.addFilter(new GlobalImageFilter());
  1. 最后,策略实现类,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);
    }
}

总结

  • 责任链将处理过程分散到具体的处理者实现中,降低了处理和调用方的耦合。

  • 设计模式的通病,会增加子类的个数。

相关文章

网友评论

    本文标题:设计模式-责任链模式

    本文链接:https://www.haomeiwen.com/subject/kqompktx.html