适配器模式把一个类的接口变换成客户端所期待的另一种接口,从而使原本因接口不匹配而无法一起工作的两个类能够在一起工作。
在生活中,我们的笔记本电脑经常需要连接很多外部设备,有时遇见电脑提供的接口与外设接口不一致。如视频接口,现在超薄笔记本提供的都是HDMI接口,但是连接到比较老的投影仪时需要VGA接口。此时我们需要一个HDMI和VGA的转换器。如下图:
适配器模式有类的适配器模式和对象的适配器模式两种不同的形式。如下图:
上图中,左边是类的适配器模式(通过继承实现,即extends关键字),右边是对象的适配器模式(通过对象组合实现)。
类的适配器模式把被适配的类的API转换成为目标类的API,其静态结构如下图:
从上图可以看出,Adaptee类并没有showInfo()方法,而客户端则其他这个方法。为使客户端能够使用Adaptee类,提供一个中间类Adapter,把Adaptee的API与Traget类的API衔接起来。Adapter与Adaptee是继承关系,这决定了这个适配器模式是类模式。
模式所涉及的角色有:
目标(Target)角色:这是我们所期待得到的接口,注意:由于这里讨论的是类适配器模式,因此目标不可以是类。
源(Adaptee)角色:现有需要适配的接口。
适配器(Adapter)角色:适配器类是本模式的核心。适配器把源接口转换成目标接口。显然,这一角色不可以是接口,而必须是具体类。
Java代码如下:
// 适配器接口 public interface Target { // 原样的将信息输出 public void show(String message); } // 被适配对象 public class Adaptee { public void showInfo(String message) { System.out.println("Adaptee=" + message); } } // 具体的适配器 public class Adapter extends Adaptee implements Target { @Override public void show(String message) { System.out.println("Adapter=" + message); super.showInfo(message); } } // 客户端 public class Client { public static void main(String[] args) { Target target = new Adapter(); target.show("hello adapter."); } }
对象的适配器模式把被适配的类的API转换成目标类的API,与类的适配器模式不同的是,对象的适配器模式不是使用继承关系连接到Adaptee类,而是使用委派关系连接到Adaptee类。如下图:
从上图中可以看出,Adaptee类并没有show()方法,而客户端则期待这个方法。为了使客户端能够使用Adaptee类,需要提供一个包装(Wrapper)类Adapter。这个包装类包装了一个Adapter与Adaptee是委派关系,这决定了这个适配器模式是对象的。
对象适配器模式设计的角色:
目标(Target)角色:这是所期待的接口,目标可以是具体的或抽象类。
源(Adaptee)角色:现有需要适配的接口。
适配器(Adapter)角色:适配器类是本模式的核心。适配器把源接口转换成目标接口,显然,这一角色必须是具体类。
Java代码如下:
// 适配器接口 public interface Target { // 原样的将信息输出 public void show(String message); } // 被适配对象 public class Adaptee { public void showInfo(String message) { System.out.println("Adaptee=" + message); } } // 具体的适配器 public class Adapter implements Target { private Adaptee adaptee; public Adapter(Adaptee adaptee) { this.adaptee = adaptee; } @Override public void show(String message) { System.out.println("Adapter=" + message); this.adaptee.showInfo(message); } } // 客户端 public class Client { public static void main(String[] args) { Target target = new Adapter(new Adaptee()); target.show("hello adapter."); } }