记得刚学Java SE的AWT(新版Swing)编程的时候,那个时候自己特别兴奋,因为学了那么久的Java了,没看到一点实在点的东西,觉得很没有成就感。后来学到Swing的时候,用它编写图形化界面,于是写了一个小小的计算器和其他简单的图形化程序。然而,在知道了Java的在图形化界面方面做的不是很好以后,心里有点失望,于是对Swing的热情也慢慢消退了。但是,我并不后悔花了点时间学Swing编程,因为在学习的过程中收获了喜悦,产生了一点小小的成就感,这些就已经够了。呵呵,话又说回来,Java的Swing编程还是值得了解或者学习一下的,因为用它来做一些演示还是挺好的。Java SE的那个Java的Applet(Java应用小程序)就简单了解一下知道Java有这么个小东西就行了,因为现在都基本宣布死亡了。
上面又说了一些废话,不过,学习Swing也是我第一次接触适配器模式,知道有Adapter这个东西。后来,学了用Java作为开发语言的Android开发后,我才更加知道了Java的Swing没有白学,因为不仅可以用Swing编程学一些小的演示程序,而且使得我特别快就上手了Android开发,对Android中的ListView的Adapter模式也特别理解,不仅如此,不知道是不是之前学了Swing还是怎么的,对Android开发非常容易就理解了。到现在,自己可以独立开发Android了。但是,知识学不完,新技术不断,对Android还需要进阶,达到更高的一个层次,让我们一起努力,一起进步。下面,直接进入正题。
定义:把一个类的接口扩展成客户端所期待的另外一个接口,使得原来不能一起使用的两个类(一个接口和一个使用该接口的类)一起工作。
使用场景:
1.
需要一个统一的输入接口,而输入端的类型不可知。这个时候,我们可以暴露一个接口适配器给客户端,让客户端自己定制。如Android的ListView的Adapter;
1.
解决接口不兼容。使得原来的一些接口在新的场景下依旧可以用,而不必写新的接口。
优点:
1.
更好的复用性。系统通过需要使用现有的类,而此类的接口不符合系统的需要,那么通过适配器模式就可以让这些功能得到更好的复用,而避免了写新的接口;
1.
更好的扩展性。通过暴露给客户端一个适配器,让客户端自己定制功能,从而更好地扩展了系统的功能,如Android中既提供了SimpleAdapter,ArrayAdapter还提供了一个抽象适配器BaseAdapter让用户自己定制。
缺点:
- 过多使用适配器,让系统杂乱不堪,不易于整体把握。如我们每次都为一个接口写一个是适配器(因为我们不需要实现该接口的所有方法)。
以生活中的裁缝铺为例
代码实现
衣服(接口)
~~~
/**
* 衣服(接口)
* @author lt
*
*/
public interface Clothes {
public int getSize();
}
~~~
具体的衣服(客户端)
~~~
/**
* 具体的衣服(客户端)
* @author lt
*
*/
public class Clothes1 implements Clothes{
/**
* 假设是180尺码
*/
@Override
public int getSize() {
return 180;
}
}
~~~
裁缝铺(适配器)
~~~
/**
* 裁缝铺(Adapter)
* @author lt
*
*/
public class TailorShop implements Clothes{
private Clothes clothes;
public TailorShop(Clothes clothes){
this.clothes = clothes;
}
/**
* 缩短五厘米
*/
@Override
public int getSize() {
return clothes.getSize()-5;
}
/**
* 将衣服拉长5厘米
* @return
*/
public int largen(){
return clothes.getSize()+5;
}
}
~~~
这里的裁缝铺是把衣服缩短5厘米,当然,裁缝铺也可以将衣服变长,也不是固定就是5厘米哦,我们可以用一个参数来让客户端指定修剪长度,如我们将裁缝铺角色改造。
~~~
/**
* 裁缝铺(Adapter)
* @author lt
*
*/
public class TailorShop implements Clothes{
private Clothes clothes;
/**
* 要修剪的长度,正数为拉长,负数缩短
*/
private int ds;
public TailorShop(Clothes clothes,int ds){
this.clothes = clothes;
this.ds = ds;
}
/**
* 缩短五厘米
*/
@Override
public int getSize() {
return clothes.getSize()+ds;
}
}
~~~
当然,裁缝铺的功能不仅是改变衣服的尺寸哦,还有缝补衣服。这里就不扩展了,要扩展也就添加方法的事了。
测试(有图有真相):
~~~
public class Test {
public static void main(String[] args) {
// 小明最近长了5里面,原来180,现在185了,但衣服还是180的
Clothes clothes = new Clothes1();
System.out.println("原来的衣服尺码:"+clothes.getSize());
// 小明说拉长5厘米
TailorShop tailorShop = new TailorShop(clothes,5);
System.out.println("经过裁缝捕裁剪后衣服的尺码:"+tailorShop.getSize());
}
}
~~~
结果(Run As):
![这里写图片描述](https://box.kancloud.cn/2016-03-17_56ea5b37a8806.jpg "")
裁缝铺修剪完后,小明顿时非常开心地穿起了原来自己喜欢但穿不了的衣服高兴地…
这个例子向我们演示了两个类(小明和衣服)原本不能一起工作,后来经过适配器(裁缝铺)修剪后又可以一起工作了(小明又穿上那件自己喜欢的衣服了)。其实,这个是对象适配器模式,当然还可以有类适配器模式,这两种模式的区别就是前者为类进行包裹封装,后者直接扩展类(继承)。下面再以一个例子结束本文的内容。
对于下面的这个接口:
~~~
public interface DemoInterface {
public void method1();
public void method2();
public void method3();
public void method4();
public void method5();
public void method6();
// ...
}
~~~
我们在使用这个接口的时候,我们每次都要实现6个或者更多的方法,如果我们不需要实现所有的方法,那么我们可以写一个这样的适配器
~~~
public abstract class DemoAdapter implements DemoInterface{
@Override
public abstract void method1();
@Override
public void method2() {
}
@Override
public void method3() {
}
@Override
public void method4() {
}
@Override
public void method5() {
}
@Override
public void method6() {
}
}
~~~
除了我们必须要实现的method1外,其它不必实现的给个空的实现,不管他。下次,我们使用个适配器代替原来的接口,通常系统也会为我们提供这样的一个适配器,如果没有,我们可以自己写。
总结:
任何的模式都有优缺点,适配器模式也不例外,如上面的抽象适配器就有一个明显的缺点,就是将一个接口替换成了抽象类,优点就是可以不用实现我们不需要实现的方法,而只关心我们必须要实现的那些方法,缺点就是由接口变成了类,使用可能会受限,因为java不支持多重继承,但可以实现多个接口。