Android责任链模式

责任链模式,使得每个对象都有机会去处理请求,从而避免请求的发送者和处理者之间的耦合,对于请求的发送者不需要关心具体的处理者是谁,这样就可以动态的去组织和分配的具体的处理者。

责任链的概述

责任链的描述

阎宏博士的《JAVA与模式》关于责任链的描述
责任链模式是一种对象的行为模式。在责任链模式里,很多对象由每一个对象对其下家的引用而连接起来形成一条链。请求在这个链上传递,直到链上的某一个对象决定处理此请求。发出这个请求的客户端并不知道链上的哪一个对象最终处理这个请求,这使得系统可以在不影响客户端的情况下动态地重新组织和分配责任。

责任链的uml

这里写图片描述
- Client:客户端,请求的发送者
- Handler:请求的处理者,其中的successor引用的是上层Handler对象,从而形成一个链状。
- ConcreteHandler:具体的请求的处理者

标准的责任链

当客户端Client发送请求的时候,接收端接受请求的时候,从链的第一个处理者Handler开始尝试去处理,如果第一个Handler处理成功,则该请求的处理完成,如果第一个请求没有处理成功,则交给这个Handler的successor引用的上层的Handler去处理,直到某个Handler处理成功。
在android,View measure,layout ,draw,dispathEvent,saveInsances,都是采用责任链模式去实现,从而将某个请求从发送,然后在每个处理者都相应对这个请求进行相应的处理。

责任链模式的时序图

这里写图片描述

责任链使用的场景

多个处理者

请求的发出后,每个处理者都会请求进行处理。并根据请求的不同从而对请求的处理不一样。

单个处理者

多个处理者都有机会去处理请求,但是最终是交给其中一种的处理者,客户端不必知道具体的请求处理者。只需要请求的返回值即可。

总之,在存在时序或者优先级的时候处理过程,都可能使用责任链模式。

例子

关于责任链模式的例子有很多,比如常见的申请费用,对联网请求request的处理。下面我说下,在android中的使用的一些场景。

场景一:图片的加载

需求分析:图片的加载标准是先从MemoryCache加载,如果没有加载本地文件。如果还是没有则加载Remote的图片。

uml图

这里写图片描述

代码分析

ImageHandler:定义抽象的ImageHandler,

public abstract class ImageHandler{
    protect ImageHandler superImageHandler;

    public abstract Bitmap getBitmap(String uri);

    public void setSuperImageHandler(ImageHandler handler){
        superImageHandler = handler;
    }

    public ImageHandler getSuperImageHandler(){
        return superImageHandler;
    }
}

MemoryImageHandler:从内存加载图片

public class MemoryImageHandler extends ImageHandler{
    private LruCache<String, Bitmap> mMemoryCache;

    @Override
    public Bitmap getBitmap(String uri){
        //从MemoryCache 取Bitmap
        Bitmap bitmap = getMemoryCahe(uri);

        if(bitmap == null && superImageHandler != null){
            bitmap = superImageHandler.getBitmap(uri);
            //保存到MemoryCache
            saveMemoryCache(uri,bitmap);
        }

        return bitmap;
    }
}

FileImageHandler:从文件加载图片

public class FileImageHandler extends ImageHandler{

    @Override
    public Bitmap getBitmap(String uri){
        //从File 中取Bitmap 
        Bitmap bitmap = getFileBitmap(uri);

        if(bitmap == null && superImageHandler != null){
            bitmap = superImageHandler.getBitmap(uri);
            //保存到File
            saveFile(uri);
        }
        return bitmap;
    }
}

RemoteImageHandler :从远程服务器加载图片

public class RemoteImageHandler extends ImageHandler{
    @Override
    public Bitmap getBitmap(String uri){
        //remote net 中取Bitmap 
        Bitmap bitmap = getRemoteBitmap(uri);
        return bitmap;
    }
}

ImageHandlerManager:动态组织和分配具体的ImageHandler

public class ImageHandlerManager{
    private ImageHandler firstHandler;
    private ImageHandler secondHandler;
    private ImageHandler thirdHandler;

    public ImageHandlerMangaer(){
        firstHandler = new MemoryImageHandler();
        secondHandler = new FileImageHandler();
        thirdHandler = new RemoteImageHandler();

        firstImageHandler.setSuperImageHandler(secondHandler);
        secondHandler.setSuperImageHandler(thirdHandler);
    }

    public Bitmap getBitmap(String uri){
        firstImageHandler.getBitmap(uri);
    }
}

MainActivity:Client

ImageHandlerManager imageHandlerManager = new ImageHandlerManager();
Bitmap imageBitmap = imageHandlerManager.getBitmap(uri);

从上面可以看出,加载的图片的三种发式,通过动态去处理加载图片的请求,并对这个请求的进行相应的处理(保存的操作),使用责任链模式,使得三种ImageHander均有机会去处理到这个请求,同时对这个请求做相应的处理,满足使用情境1.

场景二 adapter的复用

需求分析:对于一些比较容易的复用的adapter,我们应该尽量抽取出来,并共用着,但是通常的一个列表视图是存在的多类型的情况下,所以我们就需要一个WarpperAdapter去包装下我们的Adapter.但是这个时候,又存在一个问题就是我们想在里面的adapter去notify的时候,外面包装的WarpperAdapter是没有去的notify的。解决这一问题,通常有两种方案,一种就是利用责任链模式来实现,还有一种就是监听的方式实现,理论上推荐第一种。

代码分析

我们需要实现下面这样子的多type的视图结构
这里写图片描述

首先基本的BaseAdapter为

public abstract class BaseAdapter<T> extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
    protected BaseAdapter wrapperAdapter;
    protected Context context;
    protected List<T> dataList;

    {
        dataList = new ArrayList<>();
    }

    public BaseAdapter(Context context) {
        this.context = context;
    }

    public void setDataList(@NonNull List<T> dataList) {
        this.dataList = dataList;
    }

    /**
     * 刷新数据,尽量使用这个方法,而不是notifyDataSetChanged();
     */
    public void requestNotify() {
        if (wrapperAdapter != null) {
            wrapperAdapter.notifyDataSetChanged();
        } else {
            notifyDataSetChanged();
        }
    }

    public void setWrapperAdapter(BaseAdapter wrapperAdapter){
        this.wrapperAdapter = wrapperAdapter;
    }

    public void addDataList(@NonNull List<T> dataList) {
        this.dataList.addAll(dataList);
    }

    @Override
    public int getItemCount() {
        return dataList.size();
    }
}

注意上面的requestNotify的方法,先检测有没有包装的Adapter,从而将请求分配给上一层或者自己。注意这个方法,这个是将Adapter 和mWarpperAdapter行成责任链模式。

接下来看下里面带图片的Adapter:用来展示图片的item的

public class CategoryListAdapter extends BaseRecyclerAdapter<PlayListModel> {

    public CategoryListAdapter(Activity activity) {
        super(activity);
    }

    @Override
    public CategoryListAdapter onCreateViewHolder(ViewGroup parent, int viewType) {
        return new CategoryViewHolder(mActivity, parent);
    }

    @Override
    public void onBindViewHolder(CategoryListAdapter viewHolder, int position) {
        onBindViewHolder(viewHolder, position, false);
    }

    public void onBindViewHolder(CategoryListAdapter holder, int position, boolean listEnd) {

        PlayListModel playListModel = mDataList.get(position);
        final String playlist_name = playListModel.getName();
        final String playlist_image = playListModel.getImage();
        final int playlist_counts = playListModel.getCount();
        final int playlist_id = playListModel.getId();

        holder.itemView.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                VideoPlayListActivity.start(mActivity, playlist_id, playlist_name, playlist_image, playlist_counts);

                if(mOnClickListener!=null){
                    mOnClickListener.onClick(holder.itemView,position);
                }
            }
        });
    }
}

紧接着是标题的item的adapter

public class CategoryNameAdapter extends BaseRecyclerAdapter<StringCategoryNameViewHolder> {

    public CategoryNameAdapter(Activity activity) {
        super(activity);
    }

    @Override
    public CategoryNameViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        return new CategoryNameViewHolder(mActivity, parent);
    }

    @Override
    public void onBindViewHolder(CategoryNameViewHolder viewHolder, int position) {
        holder.mCategoryName.setText(mDataList.get(position));
    }

    @Override
    public int getItemCount() {
        return mDataList.size();
    }
}

最后就是重点将两个Adapter包装在一起的WarpperAdapter;

public class VideoCategoryListAdapter extends BaseAdapter {
    private Activity mActivity;

    private static final int CATEGORYLIST_ADAPTER_TYPE = 2;
    private static final int CATEGORY_LIST_NAME_TYPE = 1;

    private CategoryListAdapter mNormalAdapter;
    private CategoryNameAdapter mNameAdapter;

    private List<PlayListModel> mPlayListDatas = new ArrayList<>();
    private Map<Integer, Integer> mCategoryListCountsMap = new HashMap<>();
    private List<String> mNames = new ArrayList<>();


    public VideoCategoryListAdapter(Activity activity) {
        mActivity = activity;
        mNormalAdapter = new CategoryListAdapter(activity);
        mNameAdapter = new CategoryNameAdapter(activity);

        mNormalAdapter.setWrapperAdapter(this);
        mNameAdapter.setWrapperAdapter(this);
    }

    @Override
    public int getItemViewType(int position) {
        int count = 0;
        for (int i = 0; i < mCategoryListCountsMap.size(); i++) {
            if (position == count + i) {
                return CATEGORY_LIST_NAME_TYPE;
            }
            count += mCategoryListCountsMap.get(i);
        }
        return CATEGORYLIST_ADAPTER_TYPE;
    }

    @Override
    public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        switch (viewType) {
            case CATEGORY_LIST_NAME_TYPE:
                return new CategoryNameViewHolder(mActivity, parent);

            default:
            case CATEGORYLIST_ADAPTER_TYPE:
                return new CategoryViewHolder(mActivity, parent);
        }
    }

    @Override
    public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
        int type = getItemViewType(position);
        int offset = 0;
        int count = 0;
        boolean isSongListEnd = false;

        for (int i = 0; i < mCategoryListCountsMap.size(); i++) {
            if (position >= count + i) {//0+0  //5+1  //18+2
                count += mCategoryListCountsMap.get(i);
                offset++;
            }
            if (position == count + i - 1) {
                isSongListEnd = true;
            }
        }

        switch (type) {
            case CATEGORY_LIST_NAME_TYPE:
                mNameAdapter.onBindViewHolder(holder, offset - 1);
                break;
            case CATEGORYLIST_ADAPTER_TYPE:
                mNormalAdapter.onBindViewHolder(holder, position - offset, isSongListEnd);
                break;
        }

    }

    @Override
    public int getItemCount() {
        return mNameAdapter.getItemCount() + mNormalAdapter.getItemCount();
    }

}    

关于逻辑大家可以跳过,只需要注意在构造器的时候,通过setWrapperAdapter()的方式,将VideoCategoryListAdapter和CategoryListAdapter以及CategoryNameAdapter进行绑定,从而无论你在任何时候想刷新的时候,只要的调用requestNotify既可以,无论是VideoCategoryListAdapter的对象,还是CategoryListAdapter的对象,或者CategoryNameAdapter的对象。

总结

关于的责任链模式,其实日常使用的情况的还是较多,理论上满足时序,链状,优先级等特点,都可以尝试着使用责任链模式来重构一次代码。毕竟责任链能够有效的请求和处理者进行耦合。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值