适配器模式
定义:
适配器模式把一个类的接口转换成客户端所期待的另一种接口,从而使原本接口不匹配而无法一起工作的两个类能在一起工作
使用场景
1、系统需要使用现在的类,而此类的借口不符合系统的需要,即接口不兼容
2、想要建立一个可以重复使用的类,用于与一些彼此之间没有太大关联的一些类,包括可能将来引进的类一起工作
3、需要一个统一的输出接口,而输入端的类型不可预知
适配器模式写法
适配器模式分两种类型其UML图如下:
1、类适配器模式
- 目标(Target)角色:这就是所期待得到的接口。注意:由于这里讨论的是类适配器模式,因此目标不可以是类
- 源(Adapee)角色:现在需要适配的接口。
适配器(Adaper)角色:适配器类是本模式的核心。适配器把源接口转换成目标接口。显然,这一角色不可以是接口,而必须是具体类
我们知道额定电压是220V,但是我们真正使用的时候都需要转换一下,比如说手机充电器的电压为5V,那么适配器就是起这个转换的作用,代码如下:
//Target角色
public interface FiveVolt{
public int getVolt5();
}
//Adaptee角色,需要被转换的角色
public class Volt220{
public int getVolt220{} {
return 220;
}
}
//Adapter角色,将220V的电压转换成5V的电压
public class VoltAdapter extends Volt220 implements FiveVolt{
@Override
public int getVolt5() {
return 5;
}
}
//调用
VoltAdapter adapter = new VoltAdapter();
adapter.getVolt5();
2、对象适配器模式
- 对象的适配依赖于对象的组合,而不是类适配中的继承,我们直接用例子说明
//Target角色
public interface FiveVolt{
public int getVolt5();
}
//Adaptee角色,需要被转换的对象
public class Volt220{
public int getVolt220(){
return 220;
}
}
//对象适配器模式
public class VoltAdapter implements FiveVolt{
Volt220 mVolt220;
public VoltAdapter(Volt220 adaptee) {
mVolt220 = adaptee;
}
public int getVolt220() {
return mVolt220.getVolt220();
}
@Override
public int getVolt5() {
return 5;
}
}
//调用
VoltAdapter adapter = new VoltAdapter(new Volt220());
adapter.getVolt5();
这种实现方式直接将要被适配的对象传递到Adapter中,使用组合的形式实现接口兼容的效果,这种比类适配器方式更加灵活,而且被适配对象中的方法不会暴露出来,而类适配器中由于继承了被适配对象,因此Adapter类中会出现被适配对象类的方法,这使得Adapter中出现一些奇怪的接口,用户使用不方便,因此推荐使用对象适配器
ListView中的适配器模式分析
由于RecyclerView是对ListView的一个优化和提高,其中的核心内容是基本一致的,所以在借助ListView来简要说明适配器模式
在实际开发中Adapter通常还应用于输入类型不确定但是输出类型统一的情况,比如说ListView,itemView是各不相同的,但是最终都是属于View类型的,ListView只是需要知道getView返回的是View即可,Adapter用来隔离变化,将ListView需要的关于itemVeiw接口抽象到Adapter对象中,并且在ListView内服调用Adapter这些接口完成布局操作,这样只要实现了Adapter的接口,并且将该Adapter设置给ListView,ListView就可以按照用户设定的UI效果显示每一条数据
我们先来看看ListView的源码:
//发现其中没有Adapter
public class ListView extends AbsListView {
......
}
但是ListView是继承AbsListView,AbsListView是一个列表控件的抽象,我们跟进:
public abstract class AbsListView extends AdapterView<ListAdapter> implements TextWatcher,
ViewTreeObserver.OnGlobalLayoutListener, Filter.FilterListener,
ViewTreeObserver.OnTouchModeChangeListener,
RemoteViewsAdapter.RemoteAdapterConnectionCallback {
ListAdapter mAdapter;
@Override
protected void onAttachedToWindow() {
super.onAttachedToWindow();
//注册一个观察者
if (mAdapter != null && mDataSetObserver == null) {
mDataSetObserver = new AdapterDataSetObserver();
mAdapter.registerDataSetObserver(mDataSetObserver);
mDataChanged = true;
mOldItemCount = mItemCount;
//获得Item的数量
mItemCount = mAdapter.getCount();
}
}
//子类重写layoutChildren()方法来布局子视图
protected void onLayout(boolean changed, int l, int t, int r, int b) {
super.onLayout(changed, l, t, r, b);
mInLayout = true;
final int childCount = getChildCount();
if (changed) {
for (int i = 0; i < childCount; i++) {
getChildAt(i).forceLayout();
}
mRecycler.markChildrenDirty();
}
//布局Child View
layoutChildren();
mInLayout = false;
mOverscrollMax = (b - t) / OVERSCROLL_LIMIT_DIVISOR;
if (mFastScroll != null) {
mFastScroll.onItemCountChanged(getChildCount(), mItemCount);
}
}
}
在ListView中Target角色就是View,Adapter就是将ItemView输出为View的角色,Adaptee就是需要被处理的ItemVeiw,通过增加Adapter层将ItemView的操作抽象起来,ListView等集合视图通过Adapter对象获得Item的个数、数据、ItemView等从而达到适配各种数据、各种Item视图的效果。其中千变万化的部分交由用户处理,通过将getCount、getItem、getView等方法抽象出来,也就是将ItemView的构造方法交由用户处理,以达到无限适配的目的
Android源码设计模式