概念和功能
适配器模式(Adapter Pattern)是作为两个不兼容的接口之间的桥梁。这种类型的设计模式属于结构型模式。
适配器模式中的适配器功能和我们生活中用到的各种适配器功能一样——提供一个接口来将原本不契合的两个个体很好的链接起来。比如我们的手机电源适配器,用来给手机电池充电的,手机电池只能接受5V的电压,可是家里有很多电器需要使用,很多电器的电压是220V的,接入家里的电压是220V的,很多电器不需要电源适配器就能使用,可是手机想充电怎么办呢?就需要电源适配器来帮助“适配”这个电压——将220V的电压通过适配器转化成5V的电给手机充。
使用场景和方法
使用场景大抵是:1、系统需要使用现有的类,而此类的接口不符合系统的需要。 2、想要建立一个可以重复使用的类,用于与一些彼此之间没有太大关联的一些类,包括一些可能在将来引进的类一起工作,这些源类不一定有一致的接口。 3、通过接口转换,将一个类插入另一个类系中。(比如老虎和飞禽,现在多了一个飞虎,在不增加实体的需求下,增加一个适配器,在里面包容一个虎对象,实现飞的接口。)
使用方法大抵是:1、让适配器类继承某个类的对象实现需要的接口,修改指定方法。2、通过在适配器类中添加某个类的对象实现需要适配的接口。
实例分析
简单的实例:电源适配器
手机类:
public class Phone implements ElectricApp{
private int currentVolume;
private Power power;
@Override
public int charging() {
int volume = power.powerOut();
if (volume == 5) {
System.out.print("start charging ...");
currentVolume = 100;
} else {
System.out.print("volume not matched ! ...");
}
return currentVolume;
}
@Override
public void setPower(Power power) {
this.power = power;
}
public int getCurrentPower() {
return currentVolume;
}
}
供电接口:
public interface Power {
int powerOut();
}
电源:
/**
* 电源电力提供商
*/
public class PowerProvider implements Power {
private int powerVolume = 220;
@Override
public int powerOut() {
return powerVolume;
}
}
没有适配器直接供电:
Phone phone = new Phone();
PowerProvider powerProvider = new PowerProvider();
phone.setPower(powerProvider);
System.out.print("phone current volume is " + phone.charging());
肯定是充电不成功,电池电量还是0(现实中可能更严重——手机可能会烧掉)。现在就需要适配器来完成转化电压达到给手机充电的目的。
电源适配器:
/**
* 通过继承电源电力供应商重写供电电路来转化电流对手机进行供电
*/
public class PowerAdapterPhone extends PowerProvider{
@Override
public int powerOut() {
//do something to change the volume ......
return 5;
}
}
有适配器供电:
Phone phone = new Phone();
PowerAdapter4Phone powerAdapter4Phone = new PowerAdapter4Phone();
phone.setPower(powerAdapter4Phone);
System.out.print("phone current volume is " + phone.charging());
这样写很多人觉得不太“友好”,这样子定义的adapter确实起到适配的作用了,但是这么和换一个“电力供电公司”有什么区别呢?在具体业务场景中也很“不适用”。
那我们换第二种写法,让他看起来更“友好”一些。
电源适配器:
public class PowerAdapter4Phone2 implements Power {
private int volume;
private PowerProvider powerProvider;
public PowerAdapter4Phone2(PowerProvider powerProvider) {
this.powerProvider = powerProvider;
changeVolume(powerProvider.powerOut());
}
private void changeVolume(int volume) {
//original volume
int origin = volume;
//do something to change the volume ......
this.volume = 5;
}
@Override
public int powerOut() {
return volume;
}
}
有新的适配器供电:
Phone phone = new Phone();
PowerProvider powerProvider = new PowerProvider();
PowerAdapter4Phone2 powerAdapter4Phone = new PowerAdapter4Phone2(powerProvider);
phone.setPower(powerAdapter4Phone);
System.out.print("phone current volume is " + phone.charging());
这样看上去就友好很多了,没有那种“换了一家供电公司的错觉”,而是拿到了供电公司的电进行转化然后给手机供电的。但是这种方式还是有一些缺点,适配器强调的适配性他们都做的不好!现在出现一个场景,家里有了一个Z公司出产的空调,他需要的供电电压是240V,那我们在现有的基础上怎么修改?很多人想到的一个方法是修改PowerAdapter4Phone2类的changeVolume方法啊,在里面多加一个电器的判断而已。这么写可以解决问题,但是这么写这个适配器可能会“太奢侈了”,因为你每多了一个电器就要重写changeVolume方法,而且里面任意一个电器的需求电压变了都是要换掉这个适配器的,而且在更换的过程中你的任意一个电器都无法使用,而且这个类如果较为复杂那它只会变得更复杂、判断更多、代码更混乱,这不是真正的适配器。还有一个方法就是我们再新建一个适配器来适配空调的电压需求,然后再新写一个适配器,这个适配器是用来适配所有电压的,他具体实例化特定的适配器。
新写的适配器:
public class PowerAdapter<T extends ElectricApp> implements Power {
private T electicApp;
private PowerProvider powerProvider;
public PowerAdapter(T app, PowerProvider provider) {
electicApp = app;
powerProvider = provider;
}
@Override
public int powerOut() {
int volume = powerProvider.powerOut();
if (electicApp instanceof Phone) {
PowerAdapter4Phone3 powerAdapterPhone = new PowerAdapter4Phone3(powerProvider);
if (powerAdapterPhone.state != Power.UPDATING)
volume = powerAdapterPhone.powerOut();
} else if (electicApp instanceof ZAirCondition) {
PowerAdapter4AirCondition powerAdapterAirCondition = new PowerAdapter4AirCondition(powerProvider);
if (powerAdapterAirCondition.state != Power.UPDATING)
volume = powerAdapterAirCondition.powerOut();
}
return volume;
}
}
有新的适配器供电:
Phone phone = new Phone();
PowerProvider powerProvider = new PowerProvider();
PowerAdapter powerAdapter = new PowerAdapter(phone, powerProvider);
phone.setPower(powerAdapter);
System.out.print("phone current volume is " + phone.charging());
这样如果某个电器的电压需要修改就只需要修改它对应的适配器来满足新的需求,整个适配器类不需要修改,但是碰到新增的需求还是要修改这个适配器类的,写好新电器的适配器,然后在适配器相应的地方添加判断,相比较来说这么代码结构会更清晰,遇到很复杂的changeVolume方法也不怕,在具体的adapter里面修改就可以了。
Android中ListView和具体数据之间的交互也是通过一个适配器来协调的,列表视图展示什么数据?我的列表数据怎么能够按照具体需求展示出来?适配器就针对视图展示多少个相同的子项、子项的视图定义、和数据来源的关联等做对应的处理,充当这两者的沟通桥梁,达到列表按需展示的目的。