设计模式之-装饰者模式(Android应用场景介绍)

装饰者模式,就是在不改变原有对象的基础之上,将功能附加到对象上。提供了比继承更有弹性的替代方案(扩展原有对象功能),这个模式在java类中文件流读写类中比较常见。在开发中Android应用的也比较常见,咱们就先来介绍一下Android中的应用吧。

咱们先看看大神怎么用的,刷新控件想必大家都用过, SmartRefreshLayout 这个控件应该有蛮多人用过的。GitHub上有19k star了,这个框架就运用到了装饰者模式了,下面就让我一一道来。

其实这个框架刷新的头部和加载更多的底部view都用到了装饰者模式了。

首先我们先要知道这个刷新控件是有头部刷新View、中间的body和底部的加载更多View组成。而这个大神也是把这个刷新控件分成了三部分。这样方便拓展,我们的头部和底部控件可以自由定制自由组装。

下面我们切入代码(这里只贴主要代码,需要全部代码自行GitHub):

    @Override
    public void onFinishInflate() {
        super.onFinishInflate();
        final int count = super.getChildCount();
        if (count > 3) {
            throw new RuntimeException("最多只支持3个子View,Most only support three sub view");
        }

        int contentLevel = 0;
        int indexContent = -1;
        for (int i = 0; i < count; i++) {
            View view = super.getChildAt(i);
            if (isContentView(view) && (contentLevel < 2 || i == 1)) {
                indexContent = i;
                contentLevel = 2;
            } else if (!(view instanceof RefreshInternal) && contentLevel < 1) {
                indexContent = i;
                contentLevel = i > 0 ? 1 : 0;
            }
        }

        int indexHeader = -1;
        int indexFooter = -1;
        if (indexContent >= 0) {
            mRefreshContent = new RefreshContentWrapper(super.getChildAt(indexContent));
            if (indexContent == 1) {
                indexHeader = 0;
                if (count == 3) {
                    indexFooter = 2;
                }
            } else if (count == 2) {
                indexFooter = 1;
            }
        }

        for (int i = 0; i < count; i++) {
            View view = super.getChildAt(i);
            if (i == indexHeader || (i != indexFooter && indexHeader == -1 && mRefreshHeader == null && view instanceof RefreshHeader)) {
                mRefreshHeader = (view instanceof RefreshHeader) ? (RefreshHeader) view : new RefreshHeaderWrapper(view);
            } else if (i == indexFooter || (indexFooter == -1 && view instanceof RefreshFooter)) {
                mEnableLoadMore = (mEnableLoadMore || !mManualLoadMore);
                mRefreshFooter = (view instanceof RefreshFooter) ? (RefreshFooter) view : new RefreshFooterWrapper(view);
//            } else if (mRefreshContent == null) {
//                mRefreshContent = new RefreshContentWrapper(view);
            }
        }

    }

下面那个for循环里面就是我们需要看的,这里其实就是加载该控件时,把头部, 底部View分别赋值,我们可以看到 new RefreshHeaderWrapper(view)这里,这个就是我们装饰者模式的开始地方,我们点开可以看到如下代码:

/**
 * 刷新头部包装
 * Created by scwang on 2017/5/26.
 */
@SuppressLint("ViewConstructor")
public class RefreshHeaderWrapper extends InternalAbstract implements RefreshHeader/*, InvocationHandler*/ {

    public RefreshHeaderWrapper(View wrapper) {
        super(wrapper);
    }

}

就是一个简单实现类,我们接着往上点,如下:

protected View mWrappedView;
    protected SpinnerStyle mSpinnerStyle;
    protected RefreshInternal mWrappedInternal;

    protected InternalAbstract(@NonNull View wrapped) {
        this(wrapped, wrapped instanceof RefreshInternal ? (RefreshInternal) wrapped : null);
    }

    protected InternalAbstract(@NonNull View wrappedView, @Nullable RefreshInternal wrappedInternal) {
        super(wrappedView.getContext(), null, 0);
        this.mWrappedView = wrappedView;
        this.mWrappedInternal = wrappedInternal;
        if (this instanceof RefreshFooterWrapper && mWrappedInternal instanceof RefreshHeader && mWrappedInternal.getSpinnerStyle() == SpinnerStyle.MatchLayout) {
            wrappedInternal.getView().setScaleY(-1);
        } else if (this instanceof RefreshHeaderWrapper && mWrappedInternal instanceof RefreshFooter && mWrappedInternal.getSpinnerStyle() == SpinnerStyle.MatchLayout) {
            wrappedInternal.getView().setScaleY(-1);
        }
    }

可以看到这里第一个构造方法里面有个判断

 wrapped instanceof RefreshInternal ? (RefreshInternal) wrapped : null

这里直接掉下面那个构造方法,看到这句

this.mWrappedInternal = wrappedInternal;

到了这里就可以知道我们这个对象就是传过来给这个类装饰的,这个类中各种实现如下:


    @Override
    public boolean equals(Object obj) {
        if (!super.equals(obj)) {
            if (obj instanceof RefreshInternal) {
                final RefreshInternal thisView = this;
                return thisView.getView() == ((RefreshInternal)obj).getView();
            }
            return false;
        }
        return true;
    }

    @NonNull
    public View getView() {
        return mWrappedView == null ? this : mWrappedView;
    }

    @Override
    public int onFinish(@NonNull RefreshLayout refreshLayout, boolean success) {
        if (mWrappedInternal != null && mWrappedInternal != this) {
            return mWrappedInternal.onFinish(refreshLayout, success);
        }
        return 0;
    }

    @Override
    public void setPrimaryColors(@ColorInt int ... colors) {
        if (mWrappedInternal != null && mWrappedInternal != this) {
            mWrappedInternal.setPrimaryColors(colors);
        }
    }

    @NonNull
    @Override
    public SpinnerStyle getSpinnerStyle() {
        if (mSpinnerStyle != null) {
            return mSpinnerStyle;
        }
        if (mWrappedInternal != null && mWrappedInternal != this) {
            return mWrappedInternal.getSpinnerStyle();
        }
        if (mWrappedView != null) {
            ViewGroup.LayoutParams params = mWrappedView.getLayoutParams();
            if (params instanceof SmartRefreshLayout.LayoutParams) {
                mSpinnerStyle = ((SmartRefreshLayout.LayoutParams) params).spinnerStyle;
                if (mSpinnerStyle != null) {
                    return mSpinnerStyle;
                }
            }
            if (params != null) {
                if (params.height == 0 || params.height == MATCH_PARENT) {
                    for (SpinnerStyle style : SpinnerStyle.values) {
                        if (style.scale) {
                            return mSpinnerStyle = style;
                        }
                    }
                }
            }
        }
        return mSpinnerStyle = SpinnerStyle.Translate;
    }

    @Override
    public void onInitialized(@NonNull RefreshKernel kernel, int height, int maxDragHeight) {
        if (mWrappedInternal != null && mWrappedInternal != this) {
            mWrappedInternal.onInitialized(kernel, height, maxDragHeight);
        } else if (mWrappedView != null) {
            ViewGroup.LayoutParams params = mWrappedView.getLayoutParams();
            if (params instanceof SmartRefreshLayout.LayoutParams) {
                kernel.requestDrawBackgroundFor(this, ((SmartRefreshLayout.LayoutParams) params).backgroundColor);
            }
        }
    }

    @Override
    public boolean isSupportHorizontalDrag() {
        return mWrappedInternal != null && mWrappedInternal != this && mWrappedInternal.isSupportHorizontalDrag();
    }

    @Override
    public void onHorizontalDrag(float percentX, int offsetX, int offsetMax) {
        if (mWrappedInternal != null && mWrappedInternal != this) {
            mWrappedInternal.onHorizontalDrag(percentX, offsetX, offsetMax);
        }
    }

    @Override
    public void onMoving(boolean isDragging, float percent, int offset, int height, int maxDragHeight) {
        if (mWrappedInternal != null && mWrappedInternal != this) {
            mWrappedInternal.onMoving(isDragging, percent, offset, height, maxDragHeight);
        }
    }

    @Override
    public void onReleased(@NonNull RefreshLayout refreshLayout, int height, int maxDragHeight) {
        if (mWrappedInternal != null && mWrappedInternal != this) {
            mWrappedInternal.onReleased(refreshLayout, height, maxDragHeight);
        }
    }

    @Override
    public void onStartAnimator(@NonNull RefreshLayout refreshLayout, int height, int maxDragHeight) {
        if (mWrappedInternal != null && mWrappedInternal != this) {
            mWrappedInternal.onStartAnimator(refreshLayout, height, maxDragHeight);
        }
    }

    @Override
    public void onStateChanged(@NonNull RefreshLayout refreshLayout, @NonNull RefreshState oldState, @NonNull RefreshState newState) {
        if (mWrappedInternal != null && mWrappedInternal != this) {
            if (this instanceof RefreshFooterWrapper && mWrappedInternal instanceof RefreshHeader) {
                if (oldState.isFooter) {
                    oldState = oldState.toHeader();
                }
                if (newState.isFooter) {
                    newState = newState.toHeader();
                }
            } else if (this instanceof RefreshHeaderWrapper && mWrappedInternal instanceof RefreshFooter) {
                if (oldState.isHeader) {
                    oldState = oldState.toFooter();
                }
                if (newState.isHeader) {
                    newState = newState.toFooter();
                }
            }
            final OnStateChangedListener listener = mWrappedInternal;
            if (listener != null) {
                listener.onStateChanged(refreshLayout, oldState, newState);
            }
        }
    }

    @SuppressLint("RestrictedApi")
    public boolean setNoMoreData(boolean noMoreData) {
        return mWrappedInternal instanceof RefreshFooter && ((RefreshFooter) mWrappedInternal).setNoMoreData(noMoreData);
    }

这个类其实就是一个装饰类,这里没有改变传过来的mWrappedInternal对象的类,而是把它传过来给当前InternalAbstract类来拓展装饰功能。

下面是我自己实现的一个Adapter,利用了装饰者模式,不用再写那些繁琐的Viewholder。

装饰类如下,传入basic对象,然后该类对basic对象进行方法拓展:

package com.app.mode.demo.decorator.adapter;

import android.util.SparseIntArray;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;

import com.app.mode.demo.decorator.utils.Binding;
import com.app.mode.demo.decorator.utils.ViewBinding;

import java.util.List;

public abstract class BaseListAdapter extends BaseAdapter implements Basic {
    private Basic basic;

    public BaseListAdapter(Basic basic) {
        this.basic = basic;
    }

    public Basic getBasic() {
        return basic;
    }

    public abstract int getViewType(int position);

    abstract SparseIntArray getTypeViews();

    @Override
    public int getViewTypeCount() {
        return getTypeViews() == null ? 1 : getTypeViews().size();
    }

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

    @Override
    public int getCount() {
        return this.basic.getData() == null ? 0 : this.basic.getData().size();
    }

    @Override
    public T getItem(int position) {
        return this.basic.getData().get(position);
    }

    @Override
    public long getItemId(int position) {
        return position;
    }

    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        ViewBinding binding;
        if (convertView == null) {
            binding = new ViewBinding();
            if (getTypeViews() == null || getTypeViews().size() == 1) {
                convertView = getNormalLayoutId(parent);
            } else {
                convertView = getMultiView(parent, position);
            }
            convertView.setTag(binding);
        } else {
            binding = (ViewBinding) convertView.getTag();
        }
        binding.itemView = convertView;
        bindView(this.basic.getData().get(position), binding, position);
//        if (this.basic.getListener() != null && binding.getClickIds().size() > 0) {
//            for (Integer clickId : binding.getClickIds()) {
//                binding.getView(clickId).setOnClickListener(v -> basic.getListener().onChildClickListener(this, v, position));
//            }
//        }

        return convertView;
    }

    private View getNormalLayoutId(ViewGroup parent) {
        int layoutId = getTypeViews().valueAt(0);
        return LayoutInflater.from(parent.getContext()).inflate(layoutId, parent, false);
    }

    @SuppressWarnings("ConstantConditions")
    private View getMultiView(ViewGroup parent, int position) {
        int layoutId = getTypeViews().get(getItemViewType(position));
        return LayoutInflater.from(parent.getContext()).inflate(layoutId, parent, false);
    }

    public abstract void bindView(T t, Binding binding, int position);

    @Override
    public List getData() {
        return basic.getData();
    }

    @Override
    public void addData(List list) {
        basic.addData(list);
    }

    @Override
    public void addData(T t) {
        basic.addData(t);
    }

    @Override
    public void setNewData(List list) {
        basic.setNewData(list);
    }
}

被装饰的对象basic,装饰对象从下面传入:

public abstract class BaseListNormalAdapter extends BaseListAdapter {

    public BaseListNormalAdapter(List mData) {
        super(new BasicImp<>(mData));
    }

    public abstract int getItemViewId();

    @Override
    public SparseIntArray getTypeViews() {
        SparseIntArray map = new SparseIntArray();
        map.append(getItemViewId(), getItemViewId());
        return map;
    }

    @Override
    public int getViewType(int position) {
        return 0;
    }
}

这个类使用如下:

public class ListViewAdapter extends BaseListNormalAdapter {
    public ListViewAdapter(List list) {
        super(list);
    }

    @Override
    public void bindView(String itemData, Binding binding, int position) {
        binding.setTextView(android.R.id.text1, itemData);
    }

    @Override
    public int getItemViewId() {
        return android.R.layout.activity_list_item;
    }
}

这就是装饰者模式的简单应用,具体代码已上传GitHub,传送地址:GitHub

你可能感兴趣的:(Android设计模式应用)