1,适配器模式(Adapter,包装器,Wrapper)
将一个类的接口,转换成客户期待的另一个接口。适配器类让原本不兼容的类合作无间。属于结构型模式
1)类适配器模式
①概念
Adapter类,通过继承 src类,实现 dst 类接口,完成src->dst的适配。
②举例
充电器的例子。
src类,有220V电压:
public class Voltage220 {
public int output220V() {
int src = 220;
System.out.println("我是" + src + "V");
return src;
}
}
我们需要的des接口:输出5V。
public interface Voltage5 {
int output5V();
}
适配器类:将220V(src)转换为5V(des)。
public class VoltageAdapter extends Voltage220 implements Voltage5 {
@Override
public int output5V() {
int src = output220V();
System.out.println("适配器工作开始适配电压");
int dst = src / 44;
System.out.println("适配完成后输出电压:" + dst);
return dst;
}
}
③优缺点
有局限性,des必须为接口才可以使用。(java是单一继承)
2)对象的适配器模式(常用)
①概念
基本思路和类的适配器模式相同,只是将Adapter类作修改,这次不继承src类,而是持有src类的实例,以解决兼容性的问题。
即:持有 src类,实现 dst 类接口,完成src->dst的适配。
②举例
还是充电器例子:
public class VoltageAdapter2 implements Voltage5 {
private Voltage220 mVoltage220;
public VoltageAdapter2(Voltage220 voltage220) {
mVoltage220 = voltage220;
}
@Override
public int output5V() {
int dst = 0;
if (null != mVoltage220) {
int src = mVoltage220.output220V();
System.out.println("对象适配器工作,开始适配电压");
dst = src / 44;
System.out.println("适配完成后输出电压:" + dst);
}
return dst;
}
}
这和我们常用的Android中的Adapter相同。
③优缺点
根据合成复用原则,组合大于继承,
所以它解决了类适配器必须继承src的局限性问题,也不再强求dst必须是接口。
3)接口的适配器模式(默认适配器模式,Default Adapter Pattern,缺省适配器模式)
①概念
当不需要全部实现接口提供的方法时,可先设计一个抽象类实现接口,并为该接口中每个方法提供一个默认实现(空方法),那么该抽象类的子类可有选择地覆盖父类的某些方法来实现需求,它适用于一个接口不想使用其所有的方法的情况。
②举例
AnimatorListenerAdapter类,就是一个接口适配器。
属性动画ValueAnimator类,通过addListener(AnimatorListener listener)方法添加监听器,常规写法:
ValueAnimator valueAnimator = ValueAnimator.ofInt(0,100);
valueAnimator.addListener(new Animator.AnimatorListener() {
@Override
public void onAnimationStart(Animator animation) {
}
@Override
public void onAnimationEnd(Animator animation) {
}
@Override
public void onAnimationCancel(Animator animation) {
}
@Override
public void onAnimationRepeat(Animator animation) {
}
});
valueAnimator.start();
如果不想实现Animator.AnimatorListener接口的全部方法,只想监听onAnimationStart,则如下写法:
ValueAnimator valueAnimator = ValueAnimator.ofInt(0,100);
valueAnimator.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationStart(Animator animation) {
//xxxx具体实现
}
});
valueAnimator.start();
源码如下:
Adapter类:
public abstract class AnimatorListenerAdapter implements Animator.AnimatorListener,
Animator.AnimatorPauseListener {
@Override
public void onAnimationCancel(Animator animation) {
}
@Override
public void onAnimationEnd(Animator animation) {
}
@Override
public void onAnimationRepeat(Animator animation) {
}
@Override
public void onAnimationStart(Animator animation) {
}
@Override
public void onAnimationPause(Animator animation) {
}
@Override
public void onAnimationResume(Animator animation) {
}
}
对应的src:
public static interface AnimatorListener {
void onAnimationStart(Animator animation);
void onAnimationEnd(Animator animation);
void onAnimationCancel(Animator animation);
void onAnimationRepeat(Animator animation);
}
4)三种适配器模式对比
类适配器,以类给到,在Adapter里,就是将src当做类,继承,
对象适配器,以对象给到,在Adapter里,将src作为一个对象,持有。
接口适配器,以接口给到,在Adapter里,将src作为一个接口,实现。
2,场景
①系统需要使用现有的类,而这些类的接口不符合系统的接口。
②要建立一个可以重用的类,用于与一些彼此之间没有太大关联的一些类,包括一些可能在将来引进的类一起工作。
③需要一个统一的输出接口,而输入端的类型不可预知。
3,优缺点
1)优
①通过适配器,客户端可以调用同一接口,因而对客户端来说是透明的。这样做更简单、更直接、更紧凑。
②复用了现存的类,解决了现存类和复用环境要求不一致的问题。
③将目标类和适配者类解耦,通过引入一个适配器类重用现有的适配者类,而无需修改原有代码。
④一个对象适配器可以把多个不同的适配者类适配到同一个目标,也就是说,同一个适配器可以把适配者类和它的子类都适配到目标接口。
2)缺
对于对象适配器来说,更换适配器的实现过程比较复杂。
4,对比
1)适配器模式、装饰模式、外观模式对比
①意图
装饰者模式:不改变接口,但加入责任
适配器模式:将一个接口转成另一个接口
外观模式:让接口更简单
5,举例
①手机电源适配器
②ADO.NET的DataAdapter,是用作DataSet和数据源之间的适配器。DataAdapter通过映射Fill和Update来提供这一适配器。
6,Android中的适配器模式
1)概念
需要被适配的类、接口、对象,这些是我们已有的数据,简称 src(source);
最终需要的输出的数据:简称 dst (destination,即Target) ,适配器称之为 Adapter 。
一句话描述适配器模式: src->Adapter->dst,即src以某种形式(三种形式分别对应三种适配器模式)给到Adapter里,最终转化成了dst。
拿我们Android开发最熟悉的展示列表数据的三大控件:ListView,GridView,RecyclerView的Adapter来说,它们三个控件需要的是View(dst),而我们有的一般是datas(src),所以适配器Adapter就是完成了数据源datas 转化成 ItemView的工作。
2)举例
ListView的Adapter、GridView的Adapter、RecyclerView的Adapter
7,demo
package adapter;
public class Main_adapter {
public static void main(String[] args){
// 对客户端来说,调用的就是Target的Request()
Target target = new Adapter();
target.Request();
}
}
package adapter;
/**
* 客户期待的接口
* 接口、具体的类、抽象类都可以
* @author luo
*
*/
public interface Target {
public void Request();
}
package adapter;
/**
* 适配器类,把原接口Adaptee转换为目标接口Target
* 1,继承目标接口
* 2,建立一个私有的原接口
* 3,通过重写目标接口的方法,实际调用原接口的方法
* @author luo
*
*/
public class Adapter implements Target{
private Adaptee adaptee = new Adaptee();
@Override
public void Request() {
adaptee.SpecificRequest();
}
}
package adapter;
/**
* 需要适配的类
* @author luo
*
*/
public class Adaptee {
public void SpecificRequest(){
System.out.println("This is a Specific Request");
}
}