设计模式(13)——适配器模式

本文介绍适配器模式的概念和应用。

基本思想和原则

将一个类的接口变换成客户端所期待的另一种接口,从而使原本因接口不匹配而无法在一起工作的两个类能够在一起工作。

动机

当我们需要对某个类做一些修改以适应原有系统时,此时如果系统已经良好运行且修改原有模块的代价很大时,可以考虑使用适配器模式。适配器模式的引入可以最小化修改量,并让原本不兼容的模块在一起工作。

实现

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
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
// 电源抽象类
public interface Power {
public HashMap<String, Double> output(Double power);
}

// 用电器抽象类
public abstract class ElectricAppliance {
private Double ratedVoltage;
private Double ratedPower;

public ElectricAppliance(Double ratedVoltage, Double ratedPower) {
this.ratedVoltage = ratedVoltage;
this.ratedPower = ratedPower;
}

public Double getRatedPower() {
return ratedPower;
}

public Double getRatedVoltage() {
return ratedVoltage;
}

public void input(Double voltage, Double power) {
System.out.println(this.getClass().getName() + " get voltage " + voltage + "V power " + power + "W.");

if (voltage.equals(this.getRatedVoltage()) && power.equals(this.getRatedPower())) {
System.out.println(this.getClass().getName() + " work!");
} else {
System.out.println(this.getClass().getName() + " can't work!");
}
}
}

// 家用电源输出220V
public class HouseholdPower implements Power {
public HashMap<String, Double> output(Double power) {
HashMap<String, Double> res = new HashMap<>();
res.put("voltage", new Double(220));
res.put("power", power);
return res;
}
}

// 笔记本电脑,接受输入20V/60W
public class Laptop extends ElectricAppliance {
public Laptop(Double ratedVoltage, Double ratedPower) {
super(ratedVoltage, ratedPower);
}
}

// 笔记本电脑电源适配器,接受输入220V,功率60W,输出20V/60W
public class PowerAdapter extends ElectricAppliance implements Power {
public PowerAdapter(Double ratedVoltage, Double ratedPower) {
super(ratedVoltage, ratedPower);
}

public HashMap<String, Double> output(Double power) {
HashMap<String, Double> res = new HashMap<>();
res.put("voltage", new Double(20));
res.put("power", power);
return res;
}
}

public class Test {
public static void main(String[] args) {
Power householdPower = new HouseholdPower();
ElectricAppliance laptop = new Laptop(new Double(20), new Double(60));
PowerAdapter powerAdapter = new PowerAdapter(new Double(220), new Double(60));

System.out.println("----- Not used power adapter. -----");
// 家用电源直接对笔记本电脑供电,电脑无法工作
HashMap<String, Double> householdPowerOutput = householdPower.output(new Double(60));
laptop.input(householdPowerOutput.get("voltage"), householdPowerOutput.get("power"));

System.out.println();

System.out.println("----- Used power adapter. -----");
// 通过电源适配器给电脑供电,电脑正常工作
powerAdapter.input(householdPowerOutput.get("voltage"), householdPowerOutput.get("power"));
HashMap<String, Double> powerAdapterOutput = powerAdapter.output(new Double(60));
laptop.input(powerAdapterOutput.get("voltage"), powerAdapterOutput.get("power"));
}
}

输出如下:

1
2
3
4
5
6
7
8
9
----- Not used power adapter. -----
patterns.adapter.Laptop get voltage 220.0V power 60.0W.
patterns.adapter.Laptop can't work!

----- Used power adapter. -----
patterns.adapter.PowerAdapter get voltage 220.0V power 60.0W.
patterns.adapter.PowerAdapter work!
patterns.adapter.Laptop get voltage 20.0V power 60.0W.
patterns.adapter.Laptop work!

上面的代码模拟了电源适配器(Power Adapter)的工作过程,我们在用笔记本电脑时会看到电源线的一端有一个像盒子一样的东西,这东西就是电源适配器。在中国家用电源电压是220V,普通的电子产品一般额定电压也就是5V-20V左右,直接将电器接入220V的电压会损坏电器,这时就需要电源适配器来将输入电压转换成电器需要的电压。

上面的电源适配器接受220V/60W的额定输入,经过转换后,输出为20V/60W,可以直接提供给笔记本电脑使用。简单起见这里忽略了电源适配器的发热损耗,变压器的工作原理是输入功率和输出功率相等(不计损耗时)。

优点

适配器模式是一种补救模式,它可以使两个原本不兼容的类在一起工作,而这对高层模块是透明的,高层模块甚至不会知道真正处理任务的类是哪个。适配器模式的灵活性很好,当需要让两个不兼容的类一起工作时,我们就创建一个适配器,如果不需要这个适配器了,直接删除就好,不需要改动其他模块的代码。

缺点

需要注意适配器模式的使用时机,如果系统的功能正处于开发阶段,就不要使用适配器模式,这个模式是给那些已经良好运行且修改原有代码代价很大的时候使用的。