适配器模式(Adapter),将一个类的接口转换成客户希望的另外一个借口。适配器模式使得原本由于接口不兼容而不能一起工作的那些类可以一起工作。它主要应用于希望复用一些现存的类,但是接口又于复用环境要求不一致的情况。
适配器模式主要分为三类:对象适配器模式、类适配器模式、接口适配器模式。
适配器模式解析
这里主要以对象适配器为例。
角色介绍
- Target:客户所期待的接口,可以是具体的或抽象的类,也可以是接口。
- Adaptee:需要适配的类。
- Adapter:通过在内部包装一个 Adaptee 对象,把源接口转换成目标接口。
适配器模式基本代码
- Target 类:目标类。
1 | public class Target { |
2 | |
3 | public void request() { |
4 | System.out.println("普通请求!"); |
5 | } |
6 | } |
- Adaptee 类:需要适配的类。
1 | public class Adaptee { |
2 | |
3 | public void specificRequest() { |
4 | System.out.println("特殊请求!"); |
5 | } |
6 | } |
- Adapter 类:适配器类。
1 | public class Adapter extends Target { |
2 | |
3 | private Adaptee adaptee = new Adaptee(); |
4 | |
5 | |
6 | public void request() { |
7 | adaptee.specificRequest(); |
8 | } |
9 | } |
- Main 类
1 | public class Main { |
2 | |
3 | public static void main(String[] args) { |
4 | |
5 | Target target = new Adapter(); |
6 | |
7 | target.request(); |
8 | } |
9 | } |
示例
以充电器为例,充电器本身相当于 Adapter, 220V 交流电相当于被适配者 Adaptee,转换为 5V 直流电相当于目标者。
对象适配器
1 | /** |
2 | * Voltage220V |
3 | */ |
4 | public class Voltage220V { |
5 | |
6 | public int output220V() { |
7 | return 220; |
8 | } |
9 | } |
10 | |
11 | /** |
12 | * Voltage5V |
13 | */ |
14 | public interface Voltage5V { |
15 | |
16 | int output5V(); |
17 | } |
18 | |
19 | /** |
20 | * VoltageAdapter |
21 | */ |
22 | public class VoltageAdapter implements Voltage5V { |
23 | |
24 | private Voltage220V voltage220V = new Voltage220V(); |
25 | |
26 | |
27 | public int output5V() { |
28 | int output220V = voltage220V.output220V(); |
29 | |
30 | return output220V / 44; |
31 | } |
32 | } |
33 | |
34 | /** |
35 | * Main |
36 | */ |
37 | public class Main { |
38 | |
39 | public static void main(String[] args) { |
40 | |
41 | Voltage5V voltage5V = new VoltageAdapter(); |
42 | |
43 | System.out.println(voltage5V.output5V()); |
44 | } |
45 | } |
对象适配器,遵循合成复用原则,使用成本低,并且灵活。
类适配器
1 | /** |
2 | * Voltage220V |
3 | */ |
4 | public class Voltage220V { |
5 | |
6 | public int output220V() { |
7 | return 220; |
8 | } |
9 | } |
10 | |
11 | /** |
12 | * Voltage5V |
13 | */ |
14 | public interface Voltage5V { |
15 | |
16 | int output5V(); |
17 | } |
18 | |
19 | /** |
20 | * VoltageAdapter |
21 | */ |
22 | public class VoltageAdapter extends Voltage220V implements Voltage5V { |
23 | |
24 | |
25 | public int output5V() { |
26 | int output220V = this.output220V(); |
27 | |
28 | return output220V / 44; |
29 | } |
30 | } |
31 | |
32 | /** |
33 | * Main |
34 | */ |
35 | public class Main { |
36 | |
37 | public static void main(String[] args) { |
38 | |
39 | Voltage5V voltage5V = new VoltageAdapter(); |
40 | |
41 | System.out.println(voltage5V.output5V()); |
42 | } |
43 | } |
44 | ` |
由于 Java 是单继承机制,所以类适配器需要继承被适配类,有一定局限性;被适配类的方法在 Adapter 中都会暴露出来,也增加了使用的成本。但是其继承了被适配类,所以它可以根据需求重写被适配类中的方法,使得Adapter 的灵活性增强了。
接口适配器
当不需要全部实现接口提供的方法时,可先设计一个抽象类实现接口,并为该接口中每个方法提供一个默认实现(空方法),那么该抽象类的子类可有选择地覆盖父类的某些方法来实现需求。适用于一个接口不想使用其所有的方法的情况。
1 | /** |
2 | * Voltage |
3 | */ |
4 | public interface Voltage { |
5 | |
6 | int output5V(); |
7 | |
8 | int output10V(); |
9 | |
10 | int output20V(); |
11 | } |
12 | |
13 | /** |
14 | * AbstractVoltage |
15 | */ |
16 | public abstract class AbstractVoltage implements Voltage { |
17 | |
18 | |
19 | public int output5V() { |
20 | return 0; |
21 | } |
22 | |
23 | |
24 | public int output10V() { |
25 | return 0; |
26 | } |
27 | |
28 | |
29 | public int output20V() { |
30 | return 0; |
31 | } |
32 | } |
33 | |
34 | /** |
35 | * Voltage220V |
36 | */ |
37 | public class Voltage220V { |
38 | |
39 | public int output220V() { |
40 | return 220; |
41 | } |
42 | } |
43 | |
44 | /** |
45 | * Voltage5V |
46 | */ |
47 | public class Voltage5V extends AbstractVoltage { |
48 | |
49 | private Voltage220V voltage220V = new Voltage220V(); |
50 | |
51 | |
52 | public int output5V() { |
53 | int v = voltage220V.output220V(); |
54 | return v / 44; |
55 | } |
56 | } |
57 | |
58 | /** |
59 | * Main |
60 | */ |
61 | public class Main { |
62 | |
63 | public static void main(String[] args) { |
64 | |
65 | Voltage5V voltage5V = new Voltage5V(); |
66 | |
67 | System.out.println(voltage5V.output5V()); |
68 | } |
69 | } |
小结
一般地,使用一个已经存在的类,但如果它的接口,也就是它的方法和要求不相同时,就可以考虑使用适配器模式。