适配器模式
设计模式之简单讨论
适配器模式
将一个类的接口转换成客户想要的另一个接口,适配器模式使得原本由于接口不兼容而不能一起工作的那些类可以一起工作
举个例子,就像转换器或者转接头一样。你的电源插座只有两相插座,但是你的笔记本需要三相插座,那怎么办?你会去找一个三相转两相的转接器 。所以,适配器的功能就是做两头的转换。
1:重要角色
目标:目标是一个接口,该接口是客户想使用的接口
被适配者:被适配者可以是一个已存在的接口或抽象类或普通类,这个接口或抽象类或普通类需要适配
适配器:适配器是一个类,该类实现了目标接口
2:实现方式
1.类的适配器模式(采用继承实现)
2.对象适配器(采用对象组合方式实现)
3.接口适配器(采用抽象类方式实现)
2.1 类适配器
我们生活中常常听到的是电源适配器,它是用于电流变换(整流)的设备。适配器的存在,就是为了将已存在的东西(接口)转换成适合我们的需要、能被我们所利用。在现实生活中,适配器更多的是作为一个中间层来实现这种转换作用。

其中:
• Target
— 定义Client使用的与特定领域相关的接口。
• Client
— 与符合Target接口的对象协同。
• Adaptee
— 定义一个已经存在的接口,这个接口需要适配。
• Adapter
— 对Adaptee的接口与Target接口进行适配
在上面的通用类图中,Cient 类最终面对的是 Target 接口(或抽象类),它只能够使用符合这一目标标准的子类;而 Adaptee 类则是被适配的对象(也称 源角色),因为它包含specific (特殊的)操作、功能等,所以我们想要在自己的系统中使用它,将其转换成符合我们标准的类,使得 Client 类可以在透明的情况下任意选择使用 ConcreteTarget 类或是具有特殊功能的 Adatee 类。
代码示例 // 目标接口,或称为标准接口 interface Target { public void request(); } // 具体目标类,只提供普通功能 class ConcreteTarget implements Target { public void request() { System.out.println("普通类 具有 普通功能..."); } } // 已存在的、具有特殊功能、但不符合我们既有的标准接口的类 class Adaptee { public void specificRequest() { System.out.println("被适配类具有 特殊功能..."); } } // 适配器类,继承了被适配类,同时实现标准接口 class Adapter extends Adaptee implements Target{ public void request() { super.specificRequest(); } } // 测试类 public class Client { public static void main(String[] args) { // 使用普通功能类 Target concreteTarget = new ConcreteTarget(); concreteTarget.request(); // 使用特殊功能类,即适配类 Target adapter = new Adapter(); //对外使用方式没有发生变化 adapter.request(); } }
上面这种实现的适配器称为类适配器,因为 Adapter 类既继承了 Adaptee (被适配类),也实现了 Target 接口(因为 Java 不支持多继承,所以这样来实现),在 Client 类中我们可以根据需要选择并创建任一种符合需求的子类,来实现具体功能。
2.2 对象适配器
对象适配器它不是使用多继承或继承再实现的方式,而是使用直接关联,或者称为委托的方式,类图如下

代码示例 // 目标接口,或称为标准接口 interface Target { public void request(); } // 具体目标类,只提供普通功能 class ConcreteTarget implements Target { public void request() { System.out.println("普通类 具有 普通功能..."); } } // 已存在的、具有特殊功能、但不符合我们既有的标准接口的类 class Adaptee { public void specificRequest() { System.out.println("被适配类具有 特殊功能..."); } } // 适配器类,直接关联被适配类,同时实现标准接口 class Adapter implements Target{ // 直接关联被适配类 private Adaptee adaptee; // 可以通过构造函数传入具体需要适配的被适配类对象 public Adapter (Adaptee adaptee) { this.adaptee = adaptee; } public void request() { // 这里是使用委托的方式完成特殊功能 this.adaptee.specificRequest(); } } // 测试类 public class Client { public static void main(String[] args) { // 使用普通功能类 Target concreteTarget = new ConcreteTarget(); concreteTarget.request(); // 使用特殊功能类,即适配类, // 需要先创建一个被适配类的对象作为参数 此处对参数还可以在发挥 Target adapter = new Adapter(new Adaptee()); adapter.request(); } }
思考:
对象模式下适配器类持有的被适配对象如何设计?
请参见最后的适用场景
2.3 接口适配器
思考:
当存在这样一个接口,其中定义了很多很多方法,而我们现在却只想使用其中的一个到几个方法 如何处理?
代码实现 public class AdapterDemo { public static void main(String[] args) { A a = new AdapterTest(); a.a(); a.d(); } } interface A { void a(); void b(); void c(); void d(); void e(); void f(); } abstract class Adapter implements A { public void a() {} public void b() {} public void c() {} public void d() {} public void e() {} public void f() {} } class AdapterTest extends Adapter { //只需要重写自己需要的方法 public void a() { System.out.println("实现A方法被调用"); } public void d() { System.out.println("实现d方法被调用"); } }
通过如上示例可以看出:接口适配器是以抽象类作为适配 和前两种有着根本区别
3:适用场景
1:你想使用一个已经存在的类,而它的接口不符合你的需求。
2:你想创建一个可以复用的类,该类可以与其他不相关的类或不可预见的类(即那些接口可能不一定兼容的类)协同工作。
3:你想使用一些已经存在的子类,但是不可能对每一个都进行子类化匹配它们的接口。对象适配器可以适配它的父类接口----面向对象多态的使用 所以对象适配器比较灵活
优缺点:
优点:
更好的复用性和扩展性
缺点:
很多的适配器结合起来,会使系统过于过乱,不容易把握。
总结:适配器模式相对简单,精髓就是两个字“兼容”。
浙公网安备 33010602011771号