盒子
盒子
文章目录
  1. 适配器模式
    1. 类图
  2. 外观模式
    1. 类图
  3. 要点
    1. 适配器例子
    2. 外观例子

设计模式之适配器与外观模式

适配器模式

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

类图

适配器类图

用户一直在使用 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;
}

@Override
public boolean hasNext() {
return enums.hasMoreElements();
}

@Override
public E next() {
return enums.nextElement();
}

/**
* 因为Enumeration接口不支持remove操作,所以这里简单地抛出异常
*/
@Override
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
20
public 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
33
package 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();
}
}