适配器模式(AdapterPattern)属于结构型模式,提供了一种“使原本由于接口不兼容而不能一起工作的一批类,通过一个适配器进行”兼容”从而可以一起工作”的方式。
引
一个举烂的例子:家用电的电压 220V ,但是可以通过不同的变压器输出不同的电压;兼容型变压器也可以将不同的输入电压转换成相同的输出电压。
适配器是比较好理解的,就是将不同的适配者类(adaptee)通过同一个适配器(adapter)做出同样的动作,或者同一个适配者类(adaptee)通过不同的适配器(adapter)做出不同的动作。
常见的形式有:类适配器、对象适配器、接口/缺省适配器。主要的区别就是调用 adaptee 的形式不同。
正文
有一个电源(adaptee)可以输出 220V 的电压,用不同的变压器(adapter)转换成 110V 、5V 。。。
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| public class PowerSource { public void output_220V() { System.out.println("电压:220V"); } }
public interface Adapter_110V { void output_110V(); }
public interface Adapter_5V { void output_5V(); }
|
类适配器
由于 Java 不支持多继承,所以这种方式并不常用(即使可以替代为多实现)。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| public class Adapter extends PowerSource implements Adapter_110V { @Override public void output_110V() { super.output_220V(); System.out.println("电源输出了220V电压,开始变压。。。"); System.out.println("电压:110V"); } }
。。。
public static void main(String[] args) { Adapter_110V adapter_110V = new Adapter(); adapter_110V.output_110V(); }
|
类图:

对象适配器
和类适配器区别就是 Adapter 不使用继承再调用父类方法的方式,而是直接传入 Adaptee(电源) 对象:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| public class Adapter implements Adapter_110V { private PowerSource powerSource;
public Adapter(PowerSource powerSource) { this.powerSource = powerSource; }
@Override public void output_110V() { powerSource.output_220V(); System.out.println("电源输出了220V电压,开始变压。。。"); System.out.println("电压:110V"); } }
public static void main(String[] args) { Adapter_110V adapter_110V = new Adapter(new PowerSource()); adapter_110V.output_110V(); }
|
类图:

接口适配器(缺省适配器)
上述例子中,都是两个接口(转5V的接口和转110V的接口),接口适配器方式就是将不同的转换方法都放在一个一个接口 Target 中,Adapter 抽象类实现接口为每个方法提供一个默认实现,那么抽象类的子类就可以选择性的覆盖父类的某些方法来实现需求。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36
| public interface Target { void output_110V(); void output_5V(); }
public class Adapter implements Target { @Override public void output_110V() { }
@Override public void output_5V() { } }
public class Adapter110V extends Adapter { private PowerSource powerSource;
public Adapter110V(PowerSource powerSource) { this.powerSource = powerSource; }
@Override public void output_110V() { powerSource.output_220V(); System.out.println("电源输出了220V电压,开始变压。。。"); System.out.println("电压:110V"); } }
。。。
public static void main(String[] args) { Adapter adapter = new Adapter110V(new PowerSource()); adapter.output_110V(); }
|
类图:

实例
惯例,找一个 JDK 中的应用场景:IO 包中的 InputStreamReader 和 OutputStreamWriter 类分别继承了 Reader 和 Writer 接口,但是要创建这两个对象必须要分别传入一个 InputStream 和 OutputStream 的实例。
这里的 InputStreamReader 和 OutputStreamWriter 就是作为适配器,分别将 InputStream 和 OutputStream 适配到 Reader 和 Writer。

InputStreamReader(Adapter) 实现了 Reader(Target) 接口,并且关联了一个 InputStream(Adaptee),这个关联是通过 StreamDecoder 间接持有的,因为 InputStream 读入的字节流的 byte 需要经过编码后才是 char。
总
适配器模式和装饰器模式从类图上看比较相似,但是两者的目的是不一样的:适配器模式只是提供一个转换的作用,并不会改变原本的接口;而装饰器模式则是为了扩展原有的接口的功能,所以需要修改原有的接口。
菜鸟本菜,不吝赐教,感激不尽!
更多题解源码和学习笔记:github 、CSDN 、M1ng