适配器模式的用意是要改变原有接口,以便于目标接口相容。如果系统中有少量的这种需要适配的情况,则可以考虑使用适配器模式。但是如果需要大量的适配,则需要考虑重构系统。
适配器模式把一个类的接口变换成客户端所期待的另一种接口,从而使原本因接口不匹配而无法在一起工作的两个类能够在一起工作。如下图所示
【应用场景】
1.需要使用现有的类,而这些类的接口不符合现在的接口要求;
2.旧的系统开发的类已经实现了一些功能,但是客户端却只能以另外接口的形式访问,但我们不希望更改原有类 ;
例如a站能播放avi格式的视频,b站能播放mp4格式的视频,我不想改变b站的具体实现而用它来播放avi的视频。
案例编写:
一:定义好接口
/** * 一:目标接口 * @author wuLei */ public interface Movie { public void avi(); }
二:编写A站的具体实现
/** * 二:A站能播放avi格式影片 * @author wuLei */ public class Acefun implements Movie{ @Override public void avi() { System.out.println("avi格式的影片"); } }
三:我们现有的一套B站逻辑
/** * 三:B站能播放mp4格式影片 * @author wuLei */ public class Bilibili { public void mp4() { System.out.print("mp4格式的影片"); } }
四:编写一个适配器
/** * 四:适配器,万能播放盒子。 * @author wuLei */ public class QvodPlayer implements Movie{ private Bilibili bilibili; public QvodPlayer(Bilibili bilibili) { super(); this.bilibili = bilibili; } @Override public void avi() { System.out.print("正在将"); bilibili.mp4(); System.out.println("转码为avi, ....转码完成,播放成功!"); } }
五:测试【可以看出,并没有修改B站接口,但是可以通过适配,用avi( )来调用。】
/** * 五:测试 * @author wuLei */ public class Test { public static void main(String[] args) { Acefun a = new Acefun(); System.out.print("【A站】正在播放"); a.avi(); System.out.println("-----------------"); Movie b = new QvodPlayer(new Bilibili()); System.out.print("【B站】"); b.avi(); } } ===================== 【控制台输出】 【A站】正在播放avi格式的影片 ----------------- 【B站】正在将mp4格式的影片转码为avi, ....转码完成,播放成功!
JDK实例:
JDK中的java.util.Arrays类中的asList()方法就是采用的适配模式: public static <T> List<T> asList(T... a) { return new ArrayList<>(a); }
由于数组是没有size、get、set方法的,这些方法只有实现了java.util.List接口的集合类才有,
为了让数组可以对外提供这些方法,需要一个适配器对数组做适配。该适配器即为内部类:Arrays.ArrayList,
一方面它实现了List接口,对外可以提供size、get、set方法,
另一方面,它组合了一个数组对象,对内实际上操作的是数组的元素方法。具体实现如下:
private static class ArrayList<E> extends AbstractList<E>
implements RandomAccess, java.io.Serializable {
private final E[] a;
ArrayList(E[] array) {
if (array==null)
throw new NullPointerException();
a = array;
}
public int size() {
return a.length; // 实际上调用数组的length属性
}
public E get(int index) {
return a[index]; // 实际上根据数组的索引来get
}
public E set(int index, E element) {
E oldValue = a[index];
a[index] = element;
return oldValue;
}
}