适用场景
1,系统需要使用现有的类,但现有的类却不兼容。
2,需要建立一个可以重复使用的类,用于一些彼此关系不大的类,并易于扩展,以便于面对将来会出现的类。
3,需要一个统一的输出接口,但是输入类型却不可预知。
适配器模式中一共有3个角色,分别是:源角色、目标角色、适配器角色;
类适配器模式
类适配器模式是通过继承来实现适配功能的,代码如下:
我们先来定义一个源角色(即220V电压)
/**
* 类 名: AC220V
* 描 述: TODO 源角色
* 作 者: 黄加耀
* 创 建: 2019/2/11 : 19:30
* 邮 箱: huangjy19940202@gmail.com
*
* @author: jiaYao
*/
public class AC220V {
/**
* 获取220V电压
*
* @return
*/
public int output220v() {
int output220v = 220;
return output220v;
}
}
然后我们再来定义一个目标角色(即通过适配从而获取到的5V电压),这个地方我们定义的是一个接口
/**
* 类 名: DC5V
* 描 述: TODO 目标角色
* 作 者: 黄加耀
* 创 建: 2019/2/11 : 19:32
* 邮 箱: huangjy19940202@gmail.com
*
* @author: jiaYao
*/
public interface DC5V {
int dc5v();
}
然后,我们再来定义一个适配器,适配器的作用是将220V电压转换成为5V电压。我们看看适配器的代码
/**
* 类 名: Adapter
* 描 述: TODO 适配器角色
* 作 者: 黄加耀
* 创 建: 2019/2/11 : 19:33
* 邮 箱: huangjy19940202@gmail.com
*
* @author: jiaYao
*/
public class Adapter extends AC220V implements DC5V {
@Override
public int dc5v() {
int output220v = output220v();
return (output220v / 44);
}
}
这里,我们的适配器,继承于源角色并且实现目标角色,这样通过实现目标角色中的方法调用源角色中的方法进行运算,从而达到适配的效果。我们编写一个测试类看看
public class Test {
/**
* 基于类的适配器模式
*/
@org.junit.Test
public void test(){
DC5V dc5V = new Adapter();
int dc5 = dc5V.dc5v();
System.out.println("转换后的电压为:" + dc5 + " 伏...");
}
}
从代码中我们可以看到,其实适配器做的主要工作就是为了让目标角色的API可以调用到源角色的API,适配器在中间做的是一个类似的中转作用,并且不影响源角色和目标角色原有的功能和逻辑。
由于java只支持单继承,所以这里我们的目标角色定义的是一个接口。下面我们再来看看对象适配器
对象适配器
对象适配器是通过组合来实现适配器功能的,即适配器拥有源角色的实例,我们使用代码来看看:
此处源角色和目标角色两个类代码和上面是一样的,不另做介绍,我们看看适配器角色代码
/**
* 类 名: Adapter
* 描 述: TODO 适配器角色
* 作 者: 黄加耀
* 创 建: 2019/2/11 : 19:33
* 邮 箱: huangjy19940202@gmail.com
*
* @author: jiaYao
*/
public class Adapter implements DC5V {
private AC220V ac220V;
public Adapter(AC220V ac220V) {
this.ac220V = ac220V;
}
@Override
public int dc5v() {
int output220v = ac220V.output220v();
return (output220v / 44);
}
}
如上代码所示,我们的适配器中有一个有参构造,参数为源角色对象实例,适配器中有源角色对象实例引用,通过对象的引用我们进行适配转换。我们编写一个测试类看看
public class Test {
/**
* 基于对象的适配器模式
*/
@org.junit.Test
public void test(){
DC5V dc5V = new Adapter(new AC220V());
int dc5 = dc5V.dc5v();
System.out.println("输入的电压为:" + new AC220V().output220v() + " 伏...");
System.out.println("转换后的电压为:" + dc5 + " 伏...");
}
}
如上所示,我们的测试类中在创建适配器时,传入参数为源角色实例,然后通过适配器将其转换为目标角色的API。
场景
兼容老版本接口
在做版本升级的时候,对于一些要废弃的接口,我们不直接将其删除,而是暂时保留,并且标注为 deprecated,并将内部实现逻辑委托为新的接口实现。这样做的好处是,让使用它的项目有个过渡期,而不是强制进行代码修改。这也可以粗略地看作适配器模式的一个应用场景。
举个例子,JDK1.0 中包含一个遍历集合容器的类 Enumeration。JDK2.0 对这个类进行了重构,将它改名为 Iterator 类,并且对它的代码实现做了优化。但是考虑到如果将 Enumeration 直接从 JDK2.0 中删除,那使用 JDK1.0 的项目如果切换到 JDK2.0,代码就会编译不通过。为了做到兼容使用低版本 JDK 的老代码,我们可以暂时保留 Enumeration 类,并将其实现替换为直接调用 Itertor。代码示例如下所示:
public class Collections {
public static Emueration emumeration(final Collection c) {
return new Enumeration() {
Iterator i = c.iterator();
public boolean hasMoreElments() {
return i.hashNext();
}
public Object nextElement() {
return i.next():
}
}
}
}