适配器模式:把一个类的接口变换成客户端所期待的另一种接口,从而使原本因接口不匹配而无法在一起工作的两个类能够在一起工作。
示例:
定义目标接口(真正所期待的功能):
/**
* 电脑充电接口
* @author PC
*
*/
public interface ComputerPower {
/**
* 需要5V
* @return
*/
int getPower();
}
定义提供功能接口(当前已提供的功能):
/**
* 家庭供电接口
* @author PC
*
*/
public interface FamilyPower {
/**
* 默认为220V
* @return
*/
int get220Power();
}
他的真是实现类,家里面的一个插座:
/**
* 家里面的一个插座
* @author PC
*
*/
public class FamilySocket implements FamilyPower{
/**
* 从这个插座提供出来的电都是220V
*/
public int get220Power() {
return 220;
}
}
到了这里我们就可以看出来了,因为当前所提供的的接口和功能,并不是我们需要的,我们没办法直接用,也就是所谓的不兼容,所以我们需要一个适配器。
/**
* 电脑电源适配器
* @author PC
*
*/
public class PowerAdapter implements ComputerPower{
private FamilyPower power;
public PowerAdapter(FamilyPower power) {
super();
this.power = power;
}
/**
* 将220V电转换为5V
*/
public int getPower() {
int currPower = power.get220Power();
return currPower - 215;
}
}
我们真正需要功能的实现类这样写:
/**
* 我的Mac电脑
* @author PC
*
*/
public class Mac implements ComputerPower{
private PowerAdapter adapter;
public Mac(PowerAdapter adapter){
this.adapter = adapter;
}
/**
* 我需要5V的电
*/
public int getPower() {
return adapter.getPower();
}
}
可以看出来,这样我们就可以成功的适配了。
疑问:为什么非要让适配器去持有FamilyPower引用,然后去转换呢?感觉直接让Mac去持有,然后在getPower的时候转换就行了。
其实还是一个开闭原则,我们想要尽量不去修改主功能代码,比如Mac类,以及提供220V电压的FamilySocket类,去修改已经实现好的功能类会出现不可预期的错误。
所以我们就在他们中间介入一层Adapter,Adapter是一个可以随时被变化的类,不影响真正功能的流程的,比如Android里面的BaseAdapter,我们总是在构造需要样式的ListView的时候取创建一个适合的BaseAdapter,根据样式不同以及实体数据的不同而会创建出各种各样的adapter,而ListView的绘制代码根本不用变的。