定义:
将一个类的接口转换成客户希望的另外一个接口。适配器模式使得原本由于接口不兼容而不能一起工作的那些类可以一起工作。
角色:
目标(Target)角色:这就是所期待得到的接口,也就是这类的接口是符合我们要求的。
源(Adapee)角色:我们要使用的接口,但是这个接口不符合我们的要求,也就是现在需要适配的接口。
适配器(Adaper)角色:适配器类是适配器模式的核心。适配器把源接口转换成目标接口。显然,这一角色不可以是接口,而必须是具体类。
适用场景
1,系统需要使用现有的类,但现有的类却不兼容。
2,需要建立一个可以重复使用的类,用于一些彼此关系不大的类,并易于扩展,以便于面对将来会出现的类。
3,需要一个统一的输出接口,但是输入类型却不可预知。
实现
适配器模式可以简单的分为三类:类适配器模式、对象的适配器模式、接口的适配器模式
下面我们使用一个例子来说明这三者怎么使用
场景:手机充电需要将220V的交流电转化为手机锂电池需要的5V直流电,我们的demo就是写一个电源适配器,将 AC220v ——> DC5V,
1、类适配器模式
① 源角色(Adapee)也就是我们的220V电压类
package adapter;
//源目标
public class AC220 {
public int output220V(){
int output = 220;
return output;
}
}
② 目标角色,要定义为接口(不然无法适配,因为JAVA单继承) 也就是我们的5V
package adapter;
//需要转化的目标
public interface DC5 {
int outputDC5();
}
③ 适配器,也就是最主要的,将220V转为5V
package adapter;
//适配器,将220V转为5V
public class PowerAdapter extends AC220 implements DC5 {
@Override
public int outputDC5() {
int output = output220V();
return output/44;
}
}
测试输出
package adapter;
public class AdapterTest {
public static void main(String[] args) {
DC5 dc5 = new PowerAdapter();
int output = dc5.outputDC5();
System.out.println(output);
}
}
因为java单继承的缘故,Destination类必须是接口,以便于Adapter去继承Source并实现Destination,完成适配的功能,但这样就导致了Adapter里暴露了Source类的方法,使用起来的成本就增加了。
2、对象适配器模式
由于上面的类适配器存在的缺陷,我们使用对象适配器来实现上面的方法,还是使用上面的例子,我们保留AC220和DC5两个基类。这次我们不去继承AC220这个类,而是使用AC220的实例。
①②不变,③改为下面的代码
package adapter;
public class PowerAdapterObject implements DC5 {
//AC220实例
private AC220 ac220;
public PowerAdapterObject(AC220 ac220) {
this.ac220 = ac220;
}
@Override
public int outputDC5() {
int output = 0;
if(ac220!=null)
{
output = ac220.output220V()/44;
}
return output;
}
}
测试结果
package adapter;
public class AdapterTest {
public static void main(String[] args) {
DC5 dc5 = new PowerAdapterObject(new AC220());
int output = dc5.outputDC5();
System.out.println(output);
}
}
可以看到结果是一样的。相对于类适配器模式,将方法暴露给适配器且占用了适配器唯一的继承。对象适配器模式采用对象的方式来调用,可扩展性更强。但是还有一种更加可拓展性的适配器模式,接下来我们介绍这种适配器模式,它也是万能适配器。
3、接口适配器模式
对于接口适配器模式,我们就不用担着眼于220->5,我们的接口可以有更多的抽象方法,但我们只需要关心我们需要的回调方法,我们把接口比作万能适配器。
①定义我们需要转换的接口
package adint;
//定义所有接口,有5V,10v,12V,24v,
public interface DCoutput {
int output5V();
int output10V();
int output12V();
int output24V();
}
②定义源目标接口
package adint;
//源目标
public class AC220 {
public int output220V(){
int output = 220;
return output;
}
}
③定义伪实现类
package adint;
//定义伪实现接口
public abstract class Wrapper implements DCoutput {
protected AC220 ac220;
public Wrapper(AC220 ac220) {
this.ac220 = ac220;
}
@Override
public int output5V() {
return ac220.output220V();
}
@Override
public int output10V() {
return ac220.output220V();
}
@Override
public int output12V() {
return ac220.output220V();
}
@Override
public int output24V() {
return ac220.output220V();
}
}
④实现我们要转换成的接口
适配5V
package adint;
//适配5V的
public class DC5 extends Wrapper {
public DC5(AC220 ac220) {
super(ac220);
}
@Override
public int output5V() {
int output = 0;
if(ac220!=null)
{
output = ac220.output220V()/44;
}
return output;
}
}
适配10V
package adint;
//适配10V的
public class DC10 extends Wrapper {
public DC10(AC220 ac220) {
super(ac220);
}
@Override
public int output10V() {
int output = 0;
if(ac220!=null)
{
output = ac220.output220V()/22;
}
return output;
}
}
测试结果
package adint;
public class AdapterTest {
private static DCoutput coutput5 = new DC5(new AC220());
private static DCoutput coutput10 = new DC10(new AC220());
public static void main(String[] args) {
int five = coutput5.output5V();
int ten = coutput10.output10V();
System.out.println(five);
System.out.println(ten);
}
}
可以看到我们需要什么接口就可以实现
总结:
可以说Adapee的存在形式决定了适配器的名字,类适配器就是继承Adapee类,对象适配器就是持有Adapee类,接口适配器就是实现Adapee接口。
此外
在java中的InputStreamReader和OutputStreamWriter就是使用对象适配器模式,以InputStreamReader为例
查看源码
它继承Reader类(源目标),然后传入一个InputStream对象进行适配成InputStreamReader