介绍
概念:适配器模式就是把一个类的接口变成客户端所能接受的另一种接口,从而使两个不匹配无法再一起工作的两个类能够一起工作。
举例:有一块ps2接口的键盘,但是主机上只有usb接口,自己又没有能力修改主机上的接口,也是通过一个适配器完成ps2到usb的转换。
适配器模式有两种:1.类适配器模式;2.对象适配器模式。
类适配器模式
实现方式:将适配器类实现目标接口,并继承已有类。
代码实现:
Ps2.java,体现为拥有的键盘公口是ps2的。
/**
* Ps2的接口
* 用于描述目标接口的样子
*/
public interface Ps2 {
void isPs2();
}
Usb.java,体现为拥有的主机的母口是usb的
/**
* USB接口
* 用于描述已有接口的样子
*/
public interface Usb {
void isUsb();
}
Host.java,体现为拥有usb接口的主机。
public class Host implements Usb {
@Override
public void isUsb() {
System.out.println("我是用USB口的");
}
}
Adapter.java,体现为将ps2转成usb的适配器。
/**
* 实现将usb接口转成ps2接口的适配器
* 采用了类适配器模式
*/
public class Adapter extends Host implements Ps2 {
@Override
public void isPs2() {
isUsb();
}
}
以上就完成了对类适配器的构建,接下来就是尝试执行适配器(也就是将ps2的键盘插上转换头之后再连接到主机上)。
Clienter.java,类名并没有意义,不要混淆。
下面执行类适配器:
public class Clienter {
public static void main(String[] args) {
// 一个具体的对象,暴露在外部的是ps2接口的,并且是加了适配器的键盘
Ps2 p = new Adapter();
// 调用ps2接口才有的方法,说明确实是ps2接口的,而不是usb接口的
p.isPs2();
// p.isUsb(); 错误。说明确实不是usb接口的
}
}
输出如下:
我是用USB口的
Process finished with exit code 0
可以看到,打印出的是我是用USB口的,说明ps2接口的键盘最后以usb接口的方法在工作,适配成功。
对象适配器模式
实现方式:将适配器类实现目标接口,并依赖已有类。
代码实现:
Ps2.java,体现为拥有的键盘公口是ps2的。
/**
* Ps2的接口
* 用于描述目标接口的样子
*/
public interface Ps2 {
void isPs2();
}
Usb.java,体现为拥有的主机的母口是usb的
/**
* USB接口
* 用于描述已有接口的样子
*/
public interface Usb {
void isUsb();
}
Host.java,体现为拥有usb接口的主机。
public class Host implements Usb {
@Override
public void isUsb() {
System.out.println("我是用USB口的");
}
}
Adapter.java,体现为将ps2转成usb的适配器。
/**
* 对象适配器模式
* 通过实现目标接口,依赖已有接口实现
*/
public class Adapter implements Ps2 {
private Usb usb;
public Adapter(Usb usb) {
this.usb = usb;
}
@Override
public void isPs2() {
usb.isUsb();
}
}
以上是对象适配器类的代码实现,除适配器的具体类不同外,其他与类适配器相同;也就代表了同一个问题你可以选择不同的方式去实现它。
下面执行对象适配器:
public class Clienter {
public static void main(String[] args) {
// 向适配器传一个具体的对象,类似于将主机(只有usb接口)与ps2接口的键盘通过适配器连接
Ps2 ps2 = new Adapter(new Host());
// 执行ps2才能使用的方法
ps2.isPs2();
}
}
输出如下:
我是用USB口的
Process finished with exit code 0
结果与类适配器模式相同。适配成功。
适配器模式的优缺点
- 优点
可以让任何两个没有关联的类一起运行;提高了类的复用;增加了类的透明度;灵活性好。 - 缺点
过多地使用适配器,会让系统非常零乱,不易整体进行把握。比如,明明看到调用的是 A 接口,其实内部被适配成了 B 接口的实现,一个系统如果太多出现这种情况,无异于一场灾难。因此如果不是很有必要,可以不使用适配器,而是直接对系统进行重构;由于 JAVA 至多继承一个类,所以至多只能适配一个适配者类,而且目标类必须是抽象类。
使用场景
不是在详细设计时添加的,而是解决正在服役的项目的问题。