设计模式

设计模式-责任链模式

2020-10-17  本文已影响0人  h2coder

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

怎么实现责任链模式?

责任链模式优雅处理图片Url请求添加Token验证

上一篇策略模式博客中,我们使用策略模式打造了一个可替换Glide、Fresco实现的ImageLoader。但有些项目,请求图片Url需要在请求的header里面带一个token验证才能请求。

我们知道Glide有GlideUrl,可以组装url和header,所以最简单的方法:外部传入url的时候重载一个GlideUrl的方法,传进来加载就好了。但是这时候我们应该思考一下,Url类型的请求媒体是Url,如果是文件或者流再或者是其他类型呢?也要加一些验证或附加项,那么重载方法就会很多。那么责任链模式就比较适合了。

  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);
    }
}

总结

上一篇 下一篇

猜你喜欢

热点阅读