适配器模式
将一个类的接口,转换成客户期望的另一个接口。适配器让原本接口不兼容的类可以合作无间
类图

用户一直在使用 Target.request() 接口,而对应的业务是通过Adaptee.specificRequest()来完成。
适配器 Adapter 实现了Target.request() 接口。
同时引用了 Adaptee。来完成适配
或者 Adapter 可以通过 继承或者实现 Adaptee 接口,来完成适配
外观模式
提供一个统一的接口,用来访问子系统中的一群接口。外观定义了一个高层接口,让子系统更容易使用
类图

要点
- 当需要使用一个现有的类而其接口并不符合你的需要时,就使用适配器
- 当需要简化并统一一个很大的接口或者一群复杂的接口时,使用外观
- 适配器改变接口以符合客户的期望
- 外观将客户从一个复杂的子系统中解耦
- 适配器将一个对象包装起来以改变其接口,装饰着将一个对象包装起来以增加新的行为和责任,而外观将一群对象包装起来以简化其接口
装饰者模式——不改变接口,但加入责任
适配器模式——将一个接口转成另一个接口
外观模式——让接口更简单
适配器例子
Java的老一辈开发者应该比较熟悉Vector,Stack,Hashtable等集合类。它们的elements()返回一个实现了Enumeration接口的实现类。
但是自从出现Iterator以后,就很少再使用Enumeration了。
Iterator接口声明了三个方法: hasNext(),next(),remove()方法。
而Enumeration只声明了hasMoreElements()和nextElement()方法。分别对应于Iterator的hasNext和next方法。
假设现在客户端的代码只接受接口为Iterator的实现集合。但是现在我们已经拥有了Enumeration集合类。所以这个时候,我们可以使用适配器模式来解决接口不兼容的问题。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/*
* 一个简单的适配器模式例子
*
* 具体角色:
* Target - Iterator
* Adaptor - EnumerationIterator
* Adaptee - Enumeration
* client - print method
*/
package pattern.adapter;
import java.util.Arrays;
import java.util.Enumeration;
import java.util.Iterator;
import java.util.Vector;
/**
* 把Enumeration接口转换成Iterator接口的适配器
* 适配器模式中的角色 - adaptor
*/
class EnumerationIterator<E> implements Iterator<E> {
/**
* 被适配的接口
* 适配器模式中的角色 - adaptee
*/
private Enumeration<E> enums;
public EnumerationIterator(Enumeration<E> enums) {
this.enums = enums;
}
public boolean hasNext() {
return enums.hasMoreElements();
}
public E next() {
return enums.nextElement();
}
/**
* 因为Enumeration接口不支持remove操作,所以这里简单地抛出异常
*/
public void remove() {
throw new UnsupportedOperationException();
}
}
使用1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20public class Main {
public static void main(String[] args) {
Vector<String> students = new Vector<String>(Arrays.asList("Benson","Steven Jobs","Bill Gates","James Gosling","Doug Lea"));
Enumeration<String> enums = students.elements(); // 接口为Enumeration,与客户端的Iterator不兼容。
print(new EnumerationIterator<String>(enums)); // EnumerationIterator为适配器,将不兼容的Enumeration转换成客户端需要的Iterator接口
}
/**
* 客户端只接受Iterator接口的实现类
* 适配器模式中的角色 - Client
*/
static void print(Iterator<String> iterator) {
while(iterator.hasNext()) {
System.out.println(iterator.next());
}
}
}
外观例子
设计原则:最少知识原则,只和你的密友谈话
一个具体的例子。DrawerFacade直接封装好了所有的动作。DrawerClient和抽屉解耦,新增或调整抽屉不需要修改DrawerClient。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
33package facade;
class DrawerOne {
public void open(){
System.out.println("第一个抽屉被打开了");
getKey();
}
public void getKey(){
System.out.println("得到第二个抽屉的钥匙");
}
}
class DrawerTwo{
public void open(){
System.out.println("第二个抽屉被打开了");
getFile();
}
public void getFile(){
System.out.println("得到这个重要文件");
}
}
class DrawerFacade{
DrawerOne darwerOne=new DrawerOne();
DrawerTwo darwerTwo=new DrawerTwo();
public void open(){
darwerOne.open();
darwerTwo.open();
}
}
public class DrawerClient{
public static void main(String []args){
DrawerFacade drawer=new DrawerFacade();
drawer.open();
}
}