Android源码之ListView的适配器模式

模式的定义

适配器模式把一个类的接口变换成客户端所期待的另一种接口,从而使原本因接口不匹配而无法在一起工作的两个类能够在一起工作。

使用场景

  用电源接口做例子,笔记本电脑的电源一般都是接受5V的电压,但是我们生活中的电线电压一般都是220V的输出。这个时候就出现了不匹配的状况,在软件开发中我们称之为接口不兼容,此时就需要适配器来进行一个接口转换。在软件开发中有一句话正好体现了这点:任何问题都可以加一个中间层来解决。这个层我们可以理解为这里的Adapter层,通过这层来进行一个接口转换就达到了兼容的目的。      适配器模式也分两种,即类适配器模式、对象适配器模式,结构图如图1、图2。   

图1图2

   如图所示,类适配器是通过实现Target接口以及继承Adaptee类来实现接口转换,而对象适配器模式则是通过实现Target接口和代理Adaptee的某个方法来实现。结构上略有不同。

角色介绍  目标(Target)角色:这就是所期待得到的接口。注意:由于这里讨论的是类适配器模式,因此目标不可以是类。源(Adapee)角色:现在需要适配的接口。

适配器(Adaper)角色:适配器类是本模式的核心。适配器把源接口转换成目标接口。显然,这一角色不可以是接口,而必须是具体类。

在上述电源接口这个示例中,5V电压就是Target接口,220v电压就是Adaptee类,而将电压从220V转换到5V就是Adapter。

具体示例类适配器模式/** * Target角色 */{();}/** * Adaptee角色,需要被转换的对象 */{() {return 220;}}{() {return 5;}}

  Target角色给出了需要的目标接口,而Adaptee类则是需要被转换的对象。Adapter则是将Volt220转换成Target的接口。对应的是Target的目标是要获取5V的输出电压,而Adaptee即正常输出电压是220V,此时我们就需要电源适配器类将220V的电压转换为5V电压,解决接口不兼容的问题。

public class Test {(String[] args) {ClassAdapter adapter = new ClassAdapter();System.out.println(“输出电压 : ” + adapter.getVolt5());}}对象适配器模式

  与类的适配器模式一样,对象的适配器模式把被适配的类的API转换成为目标类的API,与类的适配器模式不同的是,对象的适配器模式不是使用继承关系连接到Adaptee类,而是使用代理关系连接到Adaptee类。      从图2可以看出,Adaptee类 ( Volt220 ) 并没有getVolt5()方法,而客户端则期待这个方法。为使客户端能够使用Adaptee类,需要提供一个包装类Adapter。这个包装类包装了一个Adaptee的实例,从而此包装类能够把Adaptee的API与Target类的API衔接起来。Adapter与Adaptee是委派关系,这决定了适配器模式是对象的。

示例代码如下 :

/** * Target角色 */{();}/** * Adaptee角色,需要被转换的对象 */{() {return 220;}}{Volt220 mVolt220;public ObjectAdapter(Volt220 adaptee) {mVolt220 = adaptee;}() {return mVolt220.getVolt220();}() {return 5;}}

注意,这里为了节省代码,我们并没有遵循一些面向对象的基本原则。

使用示例 :

public class Test {(String[] args) {ClassAdapter adapter = new ClassAdapter();System.out.println(“输出电压 : ” + adapter.getVolt5());}}类适配器和对象适配器的权衡

  *  类适配器使用对象继承的方式,是静态的定义方式;而对象适配器使用对象组合的方式,是动态组合的方式。

  *  对于类适配器,由于适配器直接继承了Adaptee,使得适配器不能和Adaptee的子类一起工作,因为继承是静态的关系,当适配器继承了Adaptee后,就不可能再去处理Adaptee的子类了。对于对象适配器,一个适配器可以把多种不同的源适配到同一个目标。换言之,同一个适配器可以把源类和它的子类都适配到目标接口。因为对象适配器采用的是对象组合的关系,只要对象类型正确,是不是子类都无所谓。

  *  对于类适配器,适配器可以重定义Adaptee的部分行为,相当于子类覆盖父类的部分实现方法。对于对象适配器,要重定义Adaptee的行为比较困难,这种情况下,需要定义Adaptee的子类来实现重定义,然后让适配器组合子类。虽然重定义Adaptee的行为比较困难,但是想要增加一些新的行为则方便的很,而且新增加的行为可同时适用于所有的源。

  *  对于类适配器,仅仅引入了一个对象,并不需要额外的引用来间接得到Adaptee。对于对象适配器,需要额外的引用来间接得到Adaptee。

  建议尽量使用对象适配器的实现方式,多用合成/聚合、少用继承。当然,具体问题具体分析,根据需要来选用实现方式,最适合的才是最好的。   

ListView中的Adapter模式

在开发过程中,ListView的Adapter是我们最为常见的类型之一。一般的用法大致如下:

// 代码省略 ListView myListView = (ListView)findViewById(listview_id); // 设置适配器 myListView.setAdapter(new MyAdapter(context, myDatas));{private LayoutInflater mInflater;List<String> mDatas ;public MyAdapter(Context context, List<String> datas){this.mInflater = LayoutInflater.from(context);mDatas = datas ;}() {return mDatas.size();}@Overridepublic String getItem(int pos) {return mDatas.get(pos);}(int pos) {return pos;}View getView(int position, View convertView, ViewGroup parent) {ViewHolder holder = null;// Item View的复用if (convertView == null) {holder = new ViewHolder();convertView = mInflater.inflate(R.layout.my_listview_item, null);// 获取titleholder.title = (TextView)convertView.findViewById(R.id.title);convertView.setTag(holder);} else {holder = (ViewHolder)convertView.getTag();}holder.title.setText(mDatas.get(position));return convertView;}}人生最好的旅行,就是你在一个陌生的地方,

Android源码之ListView的适配器模式

相关文章:

你感兴趣的文章:

标签云: