装饰者模式,就是在不改变原有对象的基础之上,将功能附加到对象上。提供了比继承更有弹性的替代方案(扩展原有对象功能),这个模式在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