长大后想做什么?做回小孩!

0%

适配器模式

适配器模式(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
//电源(adaptee)输出220V电压
public class PowerSource {
public void output_220V() {
System.out.println("电压:220V");
}
}
//220V 转 110V
public interface Adapter_110V {
void output_110V();
}
//220V 转 5V
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
//通过继承电源(adaptee)来调用电源的方法
public class Adapter extends PowerSource implements Adapter_110V {
@Override
public void output_110V() {
super.output_220V();
System.out.println("电源输出了220V电压,开始变压。。。");
System.out.println("电压:110V");
}
}

//适配 5V 的适配器,只需要实现 Adapter_5V 接口即可
。。。

public static void main(String[] args) {
Adapter_110V adapter_110V = new Adapter();
adapter_110V.output_110V();
}

类图:

wrzr4I.png

对象适配器

和类适配器区别就是 Adapter 不使用继承再调用父类方法的方式,而是直接传入 Adaptee(电源) 对象:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
//通过关联(构造方法入参)一个电源(adaptee)对象来调用电源的方法
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();
}

类图:

wrzyCt.png

接口适配器(缺省适配器)

上述例子中,都是两个接口(转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");
}
}

//转5V的适配器同上
。。。

public static void main(String[] args) {
Adapter adapter = new Adapter110V(new PowerSource());
adapter.output_110V();
}

类图:

wrz68P.png

实例

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

这里的 InputStreamReader 和 OutputStreamWriter 就是作为适配器,分别将 InputStream 和 OutputStream 适配到 Reader 和 Writer。

wrzcgf.png

InputStreamReader(Adapter) 实现了 Reader(Target) 接口,并且关联了一个 InputStream(Adaptee),这个关联是通过 StreamDecoder 间接持有的,因为 InputStream 读入的字节流的 byte 需要经过编码后才是 char。

适配器模式和装饰器模式从类图上看比较相似,但是两者的目的是不一样的:适配器模式只是提供一个转换的作用,并不会改变原本的接口;而装饰器模式则是为了扩展原有的接口的功能,所以需要修改原有的接口。


菜鸟本菜,不吝赐教,感激不尽!

更多题解源码和学习笔记:githubCSDNM1ng