美文网首页
2019-04-12设计模式-装饰模式

2019-04-12设计模式-装饰模式

作者: 猫KK | 来源:发表于2019-04-12 17:14 被阅读0次

动态地将责任附加到对象上。想要拓展原对象地功能,而不想使用继承;也就是说,我在原来的对象上拓展空能,但是我又不想修改原来对象的代码也不想使用继承,可以考虑使用装饰模式

这里通过拓展RecyclerView的Adapter来实现RecyclerView添加头部尾部地功能,进而学习装饰模式
新建一个装饰类

//注意,装饰类需要和被装饰的类继承同样的超类或实现同样的接口
public class WrapRecyclerAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {

    private RecyclerView.Adapter mAdapter;

    //构造方法,传入需要装饰的对象
    public WrapRecyclerAdapter(RecyclerView.Adapter adapter) {
        this.mAdapter = adapter;
    }

    @NonNull
    @Override
    public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup viewGroup, int viewType) {
        
    }

     @Override
    public void onBindViewHolder(@NonNull RecyclerView.ViewHolder t, int position) {
        
    }

    @Override
    public int getItemCount() {
        
    }
}

这样,就是生成了一个装饰RecyclerView.Adapter的类,值得注意的是,装饰类的构造方法一般都需要传入被装饰的对象。接下来继续完善,增加添加移除头部、尾部的方法,并使用List保存

public class WrapRecyclerAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {

    private RecyclerView.Adapter mAdapter;
    private ArrayList<View> mHeaderViews;
    private ArrayList<View> mFooterViews;

    //构造方法,传入需要装饰的对象
    public WrapRecyclerAdapter(RecyclerView.Adapter adapter) {
        this.mAdapter = adapter;
        mHeaderViews = new ArrayList<>();
        mFooterViews = new ArrayList<>();
    }

    @NonNull
    @Override
    public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup viewGroup, int viewType) {
        
    }

     @Override
    public void onBindViewHolder(@NonNull RecyclerView.ViewHolder t, int position) {
        
    }

    @Override
    public int getItemCount() {
        
    }

    /**
     * 增加头部view
     *
     * @param header
     */
    public void addHeaderView(View header) {
        if (!mHeaderViews.contains(header)) {
            mHeaderViews.add(header);
            notifyDataSetChanged();
        }
    }

    /**
     * 增加底部view
     *
     * @param footer
     */
    public void addFooterView(View footer) {
        if (!mFooterViews.contains(footer)) {
            mFooterViews.add(footer);
            notifyDataSetChanged();
        }
    }

    /**
     * 移除头部view
     *
     * @param header
     */
    public void removeHeaderView(View header) {
        if (mHeaderViews.contains(header)) {
            mHeaderViews.remove(header);
            notifyDataSetChanged();
        }
    }

    /**
     * 移除底部view
     *
     * @param footer
     */
    public void removeFooterView(View footer) {
        if (mFooterViews.contains(footer)) {
            mFooterViews.remove(footer);
            notifyDataSetChanged();
        }
    }
}

继续完善剩下的方法。getItemCount 返回的item的条数,即为原来adapter的条数加上头部尾部的条数


    @Override
    public int getItemCount() {
        return mAdapter.getItemCount() + mHeaderViews.size() + mFooterViews.size();
    }

还有两个方法,我们不知道怎么完善,可以去参考ListView的方式,ListView自带有增加头部、尾部的功能,使用的也类似的方法,看ListView.setAdapter()方法

@Override
    public void setAdapter(ListAdapter adapter) {
        //判断是否有头部或则尾部
        if (mHeaderViewInfos.size() > 0|| mFooterViewInfos.size() > 0) {
            //有就使用wrapHeaderListAdapterInternal
            mAdapter = wrapHeaderListAdapterInternal(mHeaderViewInfos, mFooterViewInfos, adapter);
        } else {
            mAdapter = adapter;
        }
}

其实也是使用了一个装饰类wrapHeaderListAdapterInternal来实现添加头部尾部的功能,去看getItem 方法

    public Object getItem(int position) {
        // Header (negative positions will throw an IndexOutOfBoundsException)
        int numHeaders = getHeadersCount();
        if (position < numHeaders) {
            return mHeaderViewInfos.get(position).data;
        }

        // Adapter
        final int adjPosition = position - numHeaders;
        int adapterCount = 0;
        if (mAdapter != null) {
            adapterCount = mAdapter.getCount();
            if (adjPosition < adapterCount) {
                return mAdapter.getItem(adjPosition);
            }
        }

        // Footer (off-limits positions will throw an IndexOutOfBoundsException)
        return mFooterViewInfos.get(adjPosition - adapterCount).data;
    }

根据position来返回不同的view。根据这个,我们可以仿照这写

    //注意这里将viewType当作了position 使用,是因为在getItemViewType中直接返回了position
    //需要注意的是,当使用一些多布局时,修改了getItemViewType 的值,可能会出现错误
    @NonNull
    @Override
    public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup viewGroup, int position) {
        // Header (negative positions will throw an IndexOutOfBoundsException)
        int numHeaders = getHeadersCount();
        if (position < numHeaders) {
            //如果是头部,直接new RecyclerView.ViewHolder,返回头部的View
            return createHeaderOrFooterViewHolder(mHeaderViews.get(position));
        }
        // Adapter
        final int adjPosition = position - numHeaders;
        int adapterCount = 0;
        if (mAdapter != null) {
            adapterCount = mAdapter.getItemCount();
            if (adjPosition < adapterCount) {
                //如果是原来的,直接调用原来的onCreateViewHolder方法
                return mAdapter.onCreateViewHolder(viewGroup, mAdapter.getItemViewType(adjPosition));
            }
        }
        // 尾部同头部
        return createHeaderOrFooterViewHolder(mFooterViews.get(adjPosition - adapterCount));
    }

    @Override
    public int getItemViewType(int position) {
        return position;
    }

    private RecyclerView.ViewHolder createHeaderOrFooterViewHolder(View view) {
        return  new RecyclerView.ViewHolder(view) {
        };
    }

    private int getHeadersCount() {
        return mHeaderViews.size();
    }

    //同onCreateViewHolder方法
    @Override
    public void onBindViewHolder(@NonNull RecyclerView.ViewHolder t, int position) {
        int numHeaders = getHeadersCount();
        if (position < numHeaders) {
            return;
        }
        final int adjPosition = position - numHeaders;
        int adapterCount = 0;
        if (mAdapter != null) {
            adapterCount = mAdapter.getItemCount();
            if (adjPosition < adapterCount) {
                mAdapter.onBindViewHolder(t, position);
            }
        }
    }

到这里,装饰类就书写完成,在Activity中使用

        rv_decoration.layoutManager = LinearLayoutManager(this)
        var adapter = TestAdapter()
        //创建装饰类,将原来的对象传进去
        var wrapAdapter = WrapRecyclerAdapter(adapter)
        rv_decoration.adapter = wrapAdapter

        var heardView = LayoutInflater.from(this@DecorationModeActivity).inflate(R.layout.layout_title, rv_decoration, false)
        wrapAdapter.addHeaderView(heardView)
        var footerView = LayoutInflater.from(this@DecorationModeActivity).inflate(R.layout.layout_title, rv_decoration, false)
        wrapAdapter.addFooterView(footerView)

到这里就可以为RecyclerView添加头部和尾部,并且不需要修改原来的代码,这就是装饰模式的好处。
需要注意的是,这个WrapRecyclerAdapter 还是有一点小问题的,但我们只是用来学习装饰模式,就不过多的讲解了。

相关文章

网友评论

      本文标题:2019-04-12设计模式-装饰模式

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