设计模式——装饰设计模式

什么是装饰设计模式?

装饰器模式是一种用于代替继承的技术,无需通过继承增加子类就能扩展对象的新功能。使用对象的关联关系代替继承关系,更加灵活,同时避免类型体系的快速膨胀。
在不使用的继承的方式下,采用装饰设计模式可以扩展一个对象的功能,可以使一个对象变得越来越强大。

装饰模式(Decorator)也叫包装器模式(Wrapper)
装饰模式降低系统的耦合度,可以动态的增加或删除对象的职责,并使得需要装饰的具体构建类和具体装饰类可以独立变化,以便增加新的具体构建类和具体装饰类。

参考文章:
https://www.cnblogs.com/zhangtianq/p/6091047.html
https://blog.csdn.net/android_zyf/article/details/68343953
https://www.cnblogs.com/pecool/p/9534568.html

以普通手机和智能手机为例子来讲:

Phone类:

public interface Phone {

    void call();

    void sms();
}

普通手机NormalPhone类:

public class NormalPhone implements Phone {
    @Override
    public void call() {
        System.out.println("可以打电话");
    }

    @Override
    public void sms() {
        System.out.println("可以发短信");
    }
}

智能手机SmartPhone类:

public class SmartPhone implements Phone {
    private NormalPhone mPhone;

    SmartPhone(NormalPhone phone) {
        this.mPhone = phone;
    }

    @Override
    public void call() {
        mPhone.call();
        System.out.println("打电话的同时还可以发微信、看视频、玩游戏等等....");
    }

    @Override
    public void sms() {
        mPhone.sms();
    }
}

Client类:

public class Client {
    public static void main(String[] args) {
        NormalPhone normalPhone = new NormalPhone();
        normalPhone.call();
        System.out.println("-----------------");
        SmartPhone smartPhone = new SmartPhone(normalPhone);
        smartPhone.call();
    }
}

控制台输出:

可以打电话
-----------------
可以打电话
打电话的同时还可以发微信、看视频、玩游戏等等....

使用装饰设计模式实现给RecyclerView添加头部和尾部

首先要知道RecyclerView控件如何使用,可以参考下面这篇文章:
https://www.jianshu.com/p/4f9591291365

MainActivity类:

public class MainActivity extends AppCompatActivity {

    private RecyclerView recyclerView;

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_recyclerview);

        ArrayList<String> datas = new ArrayList<>();
        for (int i = 0; i < 50; i++) {
            datas.add(" data " + i);
        }


        recyclerView = findViewById(R.id.recyclerview);
        LinearLayoutManager layoutManager = new LinearLayoutManager(this);
        //设置布局管理器
        recyclerView.setLayoutManager(layoutManager);
        //设置为垂直布局,这也是默认的
        layoutManager.setOrientation(OrientationHelper.VERTICAL);
        //设置Adapter
        Adapter recycleAdapter = new Adapter(datas);


        WrapperRecyclerAdapter adapter = new WrapperRecyclerAdapter(recycleAdapter);

        recyclerView.setAdapter(adapter);

        //View headerView = LayoutInflater.from(this).inflate(R.layout.header_view, null);//todo 这样写效果不对
        View headerView = LayoutInflater.from(this).inflate(R.layout.header_view, recyclerView, false);
        View footerView = LayoutInflater.from(this).inflate(R.layout.footer_view, recyclerView, false);

        adapter.addHeaderView(headerView);
        adapter.addFooterView(footerView);
        //设置分隔线
        //recyclerView.addItemDecoration(new DividerGridItemDecoration(this));
        //设置增加或删除条目的动画
        recyclerView.setItemAnimator(new DefaultItemAnimator());

    }


}

Adapter类:

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


    private List<String> mDatas;

    public Adapter(List<String> data) {
        this.mDatas = data;
    }

    @NonNull
    @Override
    public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
        View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_recycler, parent, false);
        return new ViewHolder(v);
    }

    @Override
    public void onBindViewHolder(@NonNull ViewHolder holder, final int position) {

        Log.d("TAG", "onBindViewHolder:" + position);

        holder.mTextView.setText(mDatas.get(position));
        holder.mTextView.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Log.d("TAG", "onClick :" + position);
                mDatas.remove(position);
                notifyDataSetChanged();
            }
        });

    }


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

    static class ViewHolder extends RecyclerView.ViewHolder {

        TextView mTextView;

        public ViewHolder(View v) {
            super(v);
            mTextView = v.findViewById(R.id.tv_title);
        }
    }
}

WrapperRecyclerAdapter类:

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

    private RecyclerView.Adapter mRecyclerAdapter;//原始的Adapter,不具有添加header和footer
    ArrayList<View> mHeaderViews;
    ArrayList<View> mFooterViews;

    public WrapperRecyclerAdapter(RecyclerView.Adapter adapter) {
        this.mRecyclerAdapter = adapter;
        mHeaderViews = new ArrayList<>();
        mFooterViews = new ArrayList<>();
        mRecyclerAdapter.registerAdapterDataObserver(new RecyclerView.AdapterDataObserver() {
            @Override
            public void onChanged() {
                notifyDataSetChanged();
            }
        });
    }

    @NonNull
    @Override
    public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int postion) {
        Log.e("TAG", "onCreateViewHolder " + postion);
        if (postion < mHeaderViews.size()) {
            Log.e("TAG", "add header view");
            View headerView = mHeaderViews.get(postion);
            return createHeaderView(headerView);
        }

        int itemCount = mRecyclerAdapter.getItemCount();
        int adjPos = postion - mHeaderViews.size();
        if (adjPos < itemCount) {
            Log.e("TAG", "add item view");
            return mRecyclerAdapter.onCreateViewHolder(parent, mRecyclerAdapter.getItemViewType(adjPos));
        }
        Log.e("TAG", "add footer view");
        // footerview
        View footerView = mFooterViews.get(postion - itemCount - mHeaderViews.size());
        return createHeaderView(footerView);
    }

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

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

        Log.d("TAG", "Wrapper RecyclerAdapter onBindViewHolder:" + position);

        if (position < mHeaderViews.size()) {
            return;
        }

        int adjPos = position - mHeaderViews.size();
        if (adjPos < mRecyclerAdapter.getItemCount()) {
            mRecyclerAdapter.onBindViewHolder(holder, adjPos);
            //mRecyclerAdapter.onBindViewHolder(holder, adjPos);
        } else {
            Log.d("TAG", "adjPos getItemCount." + adjPos + "  " + mRecyclerAdapter.getItemCount());
            //fix footer view.

        }


    }

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

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

    // 添加头部
    public void addHeaderView(View v) {
        if (!mHeaderViews.contains(v)) {
            mHeaderViews.add(v);
            notifyDataSetChanged();
        }
    }

    public void removeHeaderView(View v) {
        if (mHeaderViews.contains(v)) {
            mHeaderViews.remove(v);
            notifyDataSetChanged();
        }
    }

    // 添加尾部
    public void addFooterView(View v) {
        if (!mFooterViews.contains(v)) {
            mFooterViews.add(v);
            notifyDataSetChanged();
        }
    }

    public void removeFooterView(View v) {
        if (mFooterViews.contains(v)) {
            mFooterViews.remove(v);
            notifyDataSetChanged();
        }
    }
}

为了像ListView一样可以直接调用addHeaderView,我们继承RecyclerView写一个WrapperRecyclerView:

public class WrapperRecyclerView extends RecyclerView {

    private WrapperRecyclerAdapter mWrapperRecyclerAdapter;

    public WrapperRecyclerView(Context context) {
        super(context);
    }

    public WrapperRecyclerView(Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
    }

    public WrapperRecyclerView(Context context, @Nullable AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
    }

    @Override
    public void setAdapter(Adapter adapter) {
        mWrapperRecyclerAdapter = new WrapperRecyclerAdapter(adapter);
        super.setAdapter(mWrapperRecyclerAdapter);
    }

    public void addHeaderView(View view) {
        if (mWrapperRecyclerAdapter != null) {
            mWrapperRecyclerAdapter.addHeaderView(view);
        }
    }

    public void removeHeaderView(View view) {
        if (mWrapperRecyclerAdapter != null) {
            mWrapperRecyclerAdapter.removeHeaderView(view);
        }
    }

    public void addFooterView(View view) {
        if (mWrapperRecyclerAdapter != null) {
            mWrapperRecyclerAdapter.addFooterView(view);
        }
    }

    public void removeFooterView(View view) {
        if (mWrapperRecyclerAdapter != null) {
            mWrapperRecyclerAdapter.removeFooterView(view);
        }
    }
}

MainActivity2类代码:


public class MainActivity2 extends AppCompatActivity {

    private WrapperRecyclerView recyclerView;

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_recyclerview2);

        ArrayList<String> datas = new ArrayList<>();
        for (int i = 0; i < 15; i++) {
            datas.add(" WrapperRecyclerView data " + i);
        }


        recyclerView = findViewById(R.id.recyclerview);
        LinearLayoutManager layoutManager = new LinearLayoutManager(this);
        //设置布局管理器
        recyclerView.setLayoutManager(layoutManager);
        //设置为垂直布局,这也是默认的
        layoutManager.setOrientation(OrientationHelper.VERTICAL);
        //设置Adapter
        Adapter recycleAdapter = new Adapter(datas);
        //WrapperRecyclerAdapter adapter = new WrapperRecyclerAdapter(recycleAdapter);
        recyclerView.setAdapter(recycleAdapter);

        //View headerView = LayoutInflater.from(this).inflate(R.layout.header_view, null);//todo 这样写效果不对
        View headerView = LayoutInflater.from(this).inflate(R.layout.header_view, recyclerView, false);
        View footerView = LayoutInflater.from(this).inflate(R.layout.footer_view, recyclerView, false);

        recyclerView.addHeaderView(headerView);
        recyclerView.addFooterView(footerView);
        //设置分隔线
        //recyclerView.addItemDecoration(new DividerGridItemDecoration(this));
        //设置增加或删除条目的动画
        recyclerView.setItemAnimator(new DefaultItemAnimator());

    }


}

布局文件:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    tools:context="com.ivyzh.designpatterndemo.d1_singleton_pattern.MainActivity">

    <com.ivyzh.designpatterndemo.d4_decorator_pattern.simple2.WrapperRecyclerView
        android:id="@+id/recyclerview"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        />

</LinearLayout>

说明:上面的例子有个bug,就是点击item删除的时候,会有复用bug,如下图:


删除条目的Bug.png

后面会再排查。

END.

©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容

  • Android 自定义View的各种姿势1 Activity的显示之ViewRootImpl详解 Activity...
    passiontim阅读 173,860评论 25 709
  • 用两张图告诉你,为什么你的 App 会卡顿? - Android - 掘金 Cover 有什么料? 从这篇文章中你...
    hw1212阅读 13,052评论 2 59
  • 设计模式概述 在学习面向对象七大设计原则时需要注意以下几点:a) 高内聚、低耦合和单一职能的“冲突”实际上,这两者...
    彦帧阅读 3,799评论 0 14
  • 最大公约数[1] ①定义 几个自然数公有的约数,叫做这几个数的公约数;其中最大的一个,叫做这几个数的最大公约数。 ...
    dreamsfuture阅读 4,065评论 0 1
  • 追一场春光 追一个最及时的梦
    柠柠柠萌阅读 107评论 0 0