学习教材:
Head First设计模式
前言:
适配器模式是开发过程常用的一种设计模式,对于安卓开发来说,几乎天天在和适配器模式打交道,所以在此学习适配器模式以及查看安卓中适配器模式的使用。
正文:
适配器模式能把一个类的接口变换成客户端所期待的另一种接口,从而使原本不匹配而无法在一起工作的两个,类能够在一起工作。比如生活中的插座,由于不同的国家所用的标准不同,导致国内的插头必须通过一个转接口才能适配别国的插座,这里说的转接口就是适配器(Adapter),插座代表一个要使用的类(或数据),而插头则代表要使用与自身不匹配的类的客户端。(表达的不够清晰,可以用HeadFirst书中的一个图表示)
对应的适配器模式的类图:
在这个图中可以看到,客户端要使用Adaptee的接口,而由于不匹配不能直接使用,所以通过Adapter将被适配者转化为客户可以直接使用的Target接口。
这样充满了良好的OO设计原则:使用对象组合,以修改的接口包装被适配者。并且,被适配者的任何子类都可以使用这个适配器。
这个模式是如何把客户和接口绑定起来,而不是和实现绑定起来的,我们可以使用数个适配器,每一个都负责转换不同组的后台类。或者按,也可以加上新的实现,只要他们遵循目标接口就可以。
下面通过一个实例来说明适配器模式:
假设你是一名厨师,最擅长的就是烹饪烤鸭 ~~(?﹃?) ,而有一天你在准备食材的时候发现鸭子不够了,只剩下火鸡,而又没有时间去买鸭子了,这时候你想到将火鸡伪装成鸭子,因此你就需要通过一些手段(设置适配器)来将火鸡转化为可以使用的“鸭子”了。
鸭子的接口:
/*** 鸭子接口* @author Administrator**/
public interface Duck {
//鸭子的口感public void tasteDuck();}
火鸡的接口
/*** 火鸡接口* @author Administrator**/
public interface Turkey {
//火鸡的口感public void tasteTurkey();}
鸭子的实现类
/*** 鸭子的实现类* @author Administrator**/
public class RealDuck implements Duck{
@Overridepublic void tasteDuck() {System.out.println("鸭肉松软润滑,入口即化");}}
火鸡的实现类
/*** 火鸡的实现类* @author Administrator**/
public class RealTurkey implements Turkey{
@Overridepublic void tasteTurkey() {System.out.println("火鸡肉饱满紧实,富有嚼劲");}}
将火鸡伪装成鸭子(适配器):
/*** 适配器:火鸡转化为鸭子* * @author Administrator* */// 要实现想转化成的类型接口,也就是你的客户所期望看到的接口
public class Adapter implements Duck {
// 内部含有被适配者的引用,这里代表火鸡类private Turkey turkey;public Adapter(Turkey turkey) {this.turkey = turkey;}@Overridepublic void tasteDuck() {// 实现接口中的所有的方法,这里只要实现火鸡的tasteTurkey(),表面上看起来是品尝鸭肉,其实是品尝了火鸡肉~turkey.tasteTurkey();}}
最后测试:
public class MainTest {
/*** 测试一下* * @param args*/public static void main(String[] args) {// 这时候你用火鸡代替了鸭子作为食材,虽然用的是火鸡肉,但经过适配器适配后已经看起来是鸭肉了:RealTurkey turkey = new RealTurkey();Adapter adapter = new Adapter(turkey);// 客户以为自己吃的是鸭子,其实是火鸡~~eatDuck(adapter);}// 模拟下客户,食用鸭子private static void eatDuck(Duck duck) {duck.tasteDuck();}}
这里通过适配器将火鸡伪装成鸭肉后,用户就可以直接使用火鸡了(虽然原本要求传入一个鸭子对象),打印结果为:
确实是一只火鸡!
这样就实现了通过适配器将原本不匹配的接口变成可以被用户使用的接口。
类适配器和对象适配器
适配器模式分为类适配器和对象适配器,而Java只支持单继承,所以在Java中只使用对象适配器,
关于类适配器:
类适配器要求适配器同时继承Target和Adaptee类,这样就可以直接通过方法的相互调用实现适配了。以上面火鸡的例子,火鸡和鸭子若作为基类同时让Adapter继承,可将对鸭子方法的调用转接到火鸡方法的调用上。类适配器对应的类图:
关于对象适配器:
对象适配器采用了组合的方式,Adapter包含一个被适配的对象,同时adapter实现Target目标接口,将对目标对象的操作委托给adapter包含的被适配的对象。即上面的火鸡例子。
两者的对比:
类适配器只需要使用一个适配器,不需要被继承者,不需要实现整个整个被适配者,也可以覆盖被适配者的行为,因为其采用的是继承方式。
~
对象适配器不仅可以适配一个类,还适配了其子类,所以在适配器中添加了任何行为,都可以在被适配者子类使用。
以上是对适配器模式的一个概述,下面来说:
安卓中的适配器模式:
以ListView为例,我们调用listView的setAdapter方法,查看源码:
@Overridepublic void setAdapter(ListAdapter adapter) {...}
看到传入的是一个ListAdapter对象,即适配器模式的Target接口,而对于被适配者,是不同的数据源,像是List集合,Cursor对象,所以有了ArrayAdapter和CursorAdapter分别用于适配两种数据,将它们适配成能被ListView使用的ListAdapter(其实是ListAdapter的子类BaseAdapter),下面的图很好的说明了。
同理,我们一般都会自定义一个Adapter继承BaseAdapter,就是为了将自定义的数据能更好的显示在ListView上,ListView以为自己操作的是ListAdapter,其实是我们自己定义的数据,所以我们分别重写BaseAdapter的方法来操作我们要传入的数据集合。通过适配器模式,给我们实现数据展示的方式带来了极大的便利,同时也给数据的多样性适配带来无限可能~~
最后,感谢你能阅读到这里~~ ?