从名字上就可以看出适配器是为了针对接口不匹配的情况,而做出的兼容方法,
假设我们有一个已经存在的类Adaptee,其中有一些已经存在并实现好的方法methodA。但是客户不希望调用这个类,而是希望调用一个特定的接口例如Target接口。
于是如果想要调用Adaptee.methodA()方法,创建一个Adapter类实现客户要求的Target接口,Target接口中假设客户希望调用callMethodA()方法来实现Adaptee.methodA()方法功能。能够想到的就是以下两种方式:
让Adapter类实现Target接口接口同时继承Adaptee类,这样Adapter类就继承了Adaptee.methodA(),在其callMethodA()中调用父类的methodA()方法即可。客户新建Adapter类对象,就可以通过Target接口调用Adapter.methodA()。
public class Adaptee {
public void methodA(){
System.out.println("I am the methodA in Adaptee");
}
}
public interface Target {
public void callMethodA();
public void otherMethod();
}
public class Adapter extends Adaptee implements Target {
@Override
public void callMethodA() {
super.methodA();
}
@Override
public void otherMethod() {
System.out.println("I am the otherMethod in Adapter");
}
}
public class Client {
public static void main(String[] args) {
Adapter mAdapter = new Adapter();
mAdapter.callMethodA();
mAdapter.otherMethod();
}
}
I am the methodA in Adaptee
I am the otherMethod in Adapter
让Adapter类中持有一个Adaptee类的实例,在Adapter类实现Target接口的methodA()方法时,在其中调用Adaptee实例的methodA()方法即可。
在上面的类的适配器基础上,只需要修改Adapter和客户类即可。
public class Adapter implements Target {
private Adaptee mAdaptee;
public Adapter(Adaptee mAdaptee) {
this.mAdaptee = mAdaptee;
}
@Override
public void callMethodA() {
this.mAdaptee.methodA();
}
@Override
public void otherMethod() {
System.out.println("I am the otherMethod in Adapter");
}
}
public class Client {
public static void main(String[] args) {
Adaptee mAdaptee=new Adaptee();
Adapter mAdapter = new Adapter(mAdaptee);
mAdapter.callMethodA();
mAdapter.otherMethod();
}
}
输出结果也是一样的
I am the methodA in Adaptee
I am the otherMethod in Adapter
两种模式各有利弊,类的适配器模式已经继承了Adaptee类,就没法再继承其他的类,这时它的弊端,不过好处就是逻辑比较清晰,适合只适配单一的Adaptee的情况。对象的适配器模式则没有继承的限制,采用聚合的方式来适配待适配的类。个人个倾向于对象的适配器模式这种适配器方式,耦合性更低。
适配器还有第三种模式,看起来和上面的两种适配器模式不太一样,
对于一个定义了较多方法的接口,我们实现该接口的时候,一来实现这么多的方法很麻烦。二来有些方法我们并不需要,都实现了反而混淆了重点。
为了解决这个问题,就是用一个抽象类继承该接口,并在抽象类中使用空实现来实现接口中的方法。(也不一定,有些情况抽象类中会有接口中的方法的默认实现,而继承它的子类中只需要完成其特有的一些方法,或者在原有方法的基础上进行增加。例如Android中的PhoneBase类,BaseAdapter类等)。
public interface Target {
public void A();
public void B();
public void C();
public void D();
public void E();
public void F();
}
public abstract class AbstractTarget implements Target {
@Override
public void A() {
}
//可以留一个B方法不实现,B还是抽象的,留给子类必须实现
@Override
public void C() {
System.out.println("I am C in AbstractTarget");
}
@Override
public void D() {
}
@Override
public void E() {
}
@Override
public void F() {
}
}
public class ConcreteTarget extends AbstractTarget {
@Override
public void B() {//B是必须实现的
System.out.println("I am B in ConcreteTarget");
}
@Override
public void A() {//选择性的重写A和C方法
System.out.println("I am A in ConcreteTarget");
}
@Override
public void C() {
super.C();
System.out.println("I am C in ConcreteTarget");
}
}
public static void main(String[] args) {
Target mTarget = new ConcreteTarget();
mTarget.A();
mTarget.B();
mTarget.C();
}
Android中最常见的适配器模式就属于Android中的Adapter了,其应用融合了缺省适配器模式和对象的适配器模式
抽象类BaseAdapter实现ListAdapter和SpinnerAdapter两个接口,而这两个接口都是继承自Adapter接口,这两个接口分别又定义了自己的方法
public abstract class BaseAdapter implements ListAdapter, SpinnerAdapter
不过BaseAdapter中并未实现接口中的全部方法
SimpleAdapter则继承了BaseAdapter,并实现了所有没实现的接口方法,有些BaseAdapter已经实现的方法,并没有实现。
public class SimpleAdapter extends BaseAdapter
这里就是上面的缺省适配器模式。
那么对象的适配器呢,
当我们使用SimpleAdapter时,例如:
ListView.setAdapter(new SimpleAdapter(this, getData(path),
android.R.layout.simple_list_item_1, new String[] { "title" },
new int[] { android.R.id.text1 }));
先看一下SimpleAdapter构造函数
public SimpleAdapter(Context context, List<? extends Map<String, ?>> data,
int resource, String[] from, int[] to)
其中第2个参数是一个Map的队列,对应每一个List的Item的数据,第3个参数则是展开这个Item的View的layout资源的整形ID。第4个参数from数组是第2个参数的Map的key,最后一个参数to数组则是from参数的每一个key对应的数据放置在哪个组件里。
在ListView调用onMeasure确定组件尺寸时,就会调用到mAdapter.getCount(),调用这个SimpleAdapter的getCount()函数:
public int getCount() {
return mData.size();
}
public Object getItem(int position) {
return mData.get(position);
}
间接调用之前创建SimpleAdapter时构造函数传递的data数据。
在绘制的时候,则会调用
mAdapter.getView(position, null, this)
获取适配器所适配的数据所对应的View来进行绘制。
所以这里SimpleAdapter就是对data对象的对象适配器模式,如果不使用适配器,ListView直接持有data数据当然也可以得到数据。但是ListView使用Adapter的精髓就是不需要去管数据是什么,只需要创建不同的Adapter,就可以做出不同效果,含有不同组件的ListView。