适配器模式的基本作用是将一个类的接口转换成客户希望的另外一个接口,使得原本由于接口不兼容而不能一起工作的那些类可以在一起工作。
模式中的角色
1、目标接口(Target):客户所期待的接口。目标可以是具体的或抽象的类,也可以是接口。2、需要适配的类(Adaptee):需要适配的类或适配者类。
3、适配器(Adapter):通过包装一个需要适配的对象,把原接口转换成目标接口。
在GoF的设计模式中,对适配器模式讲了两种类型,类适配器模式和对象适配器模式。由于类适配器模式通过多重继承对一个接口与另一个接口进行匹配,而C#、java等语言都不支持多重继承,因而这里只是介绍对象适配器。
何时使用适配器模式?
1、系统需要使用现有的类,但此类的接口不符合系统的需要。
2、想要建立一个可以重复使用的类,用于与一些彼此之间没有太大关联的一些类,包括一些可能在将来引进的类一起工作,这些源类不一定有一致的接口。
3、通过接口转换,将一个类插入另一个类系中。
4、两个类所做的事情相同或相似,但是具有不同接口的时候。
5、旧的系统开发的类已经实现了一些功能,但是客户端却只能以另外接口的形式访问,但我们不希望手动更改原有类的时候。
6、使用第三方组件,组件接口定义和自己定义的不同,不希望修改自己的接口,但是要使用第三方组件接口的功能。
应用实例:
1、JAVA JDK 1.1 提供了 Enumeration 接口,而在 1.2 中提供了 Iterator 接口,想要使用 1.2 的 JDK,则要将以前系统的 Enumeration 接口转化为 Iterator 接口,这时就需要适配器模式。
2、在 LINUX 上运行 WINDOWS 程序。
3、JAVA 中的 jdbc。
二、适配器模式实现实例
1、首先定义目标接口Target和一个标准实现类
Target.java
// 目标接口,或称为标准接口 public interface Target { public void request(); }
ConcreteTarget.java
// 具体目标类,只提供普通功能 public class ConcreteTarget implements Target { public void request() { System.out.println("普通类具有普通功能..."); } }
2、需要适配的类Adaptee
// 已存在的、具有特殊功能、但不符合我们既有的标准接口的类 public class Adaptee { public void specificRequest() { System.out.println("被适配类具有特殊功能..."); } }
3、适配类Adapter
/
/ 适配器类,直接组合被适配类,同时实现标准接口 public class Adapter implements Target{ // 直接组合被适配类,即持有一个被适配类的实例 private Adaptee adaptee; // 可以通过构造函数传入具体需要适配的对象实例 public Adapter (Adaptee adaptee) { this.adaptee = adaptee; } public void request() { // 这里是使用委托的方式完成特殊功能 //虽然表面看起来执行的是标准接口中的request方法,实际执行的却是被适配类中的方法 this.adaptee.specificRequest(); } }
4、测试
// 测试类 public class Test { public static void main(String[] args) { // 使用普通功能类 Target concreteTarget = new ConcreteTarget(); concreteTarget.request(); // 使用特殊功能类,即适配类, // 需要先创建一个被适配类的对象作为参数 Target adapter = new Adapter(new Adaptee()); adapter.request(); } }
注意:
Adapter 自身必须先拥有一个被适配类的对象,再把具体的特殊功能委托给这个对象来实现。使用对象适配器模式,可以使得 Adapter 类(适配类)根据传入的 Adaptee 对象定义多个构造函数,达到适配多个不同被适配类的功能。当然,此时我们可以为多个被适配类提取出一个接口或抽象类。这样看起来的话,似乎对象适配器模式更加灵活一点。
三、总结
优点:
1、通过适配器,客户端可以调用同一接口,因而对客户端来说是透明的。这样做更简单、更直接、更紧凑。
2、复用了现存的类,解决了现存类和复用环境要求不一致的问题。
3、将目标类和适配者类解耦,通过引入一个适配器类重用现有的适配者类,而无需修改原有代码。
4、一个对象适配器可以把多个不同的适配者类适配到同一个目标,也就是说,同一个适配器可以把适配者类和它的子类都适配到目标接口。
缺点:
1、过多地使用适配器,会让系统非常零乱,不易整体进行把握。
2、由于 JAVA 至多继承一个类,所以至多只能适配一个适配者类,而且目标类必须是抽象类。