前面已经说到了适配器和装饰器两种模式,两种怎么看都一样的,其实它们龙凤双胞胎。


  • 适配器

咱们先来看看适配器模式的代码。

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
//适配器接口
public interface Target {
void request(Map<String, String> boby);
}
//适配器
public class Adapter implements Target {
private Adaptee adaptee;
public Adapter(Adaptee adaptee) {
this.adaptee = adaptee;
}
//适配方法
@Override
public void request(Map<String, String> boby) {
List<String> list = new ArrayList<String>();
for(Entry<String, String> entry : boby.entrySet()) {
list.add(entry.getKey() + "-" + entry.getValue());
}
adaptee.simpleRequest((String[]) list.toArray());
}
}
//被适配
public class Adaptee {
public void simpleRequest(String[] boby) {}
}

可以看到上诉代码,这只纯粹一个被适配者和适配器的关系,那假如被适配者又是另外一个被适配者的适配器呢?呵呵~~

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
interface Target {
void request(Map<String, String> boby);
}
//适配器一号
class Adapter implements Target {
private Target2 adaptee;
public Adapter(Target2 adaptee) {
this.adaptee = adaptee;
}
@Override
public void request(Map<String, String> boby) {
List<String> list = new ArrayList<String>();
for(Entry<String, String> entry : boby.entrySet()) {
list.add(entry.getKey() + "-" + entry.getValue());
}
adaptee.simpleRequest((String[]) list.toArray());
}
}
interface Target2 {
void simpleRequest(String[] boby);
}
//适配器二号,又被适配器一号适配
class Adaptee implements Target2 {
private Adaptee2 adaptee2;
public Adaptee(Adaptee2 adaptee2) {
this.adaptee2 = adaptee2;
}
public void simpleRequest(String[] boby) {}
}
//被适配者
class Adaptee2 {
public void dickRequest(String[] boby) {}
}
public class AdapterTemplate {
public static void main(String[] args) {
Target target = new Adapter(new Adaptee(new Adaptee2()));
target.request(new HashMap<String, String>());
}
}

咱们来看,Adaptee适配Adaptee2的同时,也被Adapter所适配,最终在main方法中的代码呈现给我们的是这样的

1
Target target = new Adapter(new Adaptee(new Adaptee2()));
  • 装饰器

跟装饰器并没有什么两样。好吧,还是有区别的,让我们回头再看看装饰器怎样的?

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
//基类(接口)
public interface DecoratorTarget {
void read(byte[] bs);
}
//源基类
public class DecoratorTargetSource implements DecoratorTarget {
@Override
public void read(byte[] bs) {}
}
//源基类装饰器1
public class Decorator1 implements DecoratorTarget {
protected DecoratorTarget target;
public Decorator1(DecoratorTarget target) {
this.target = target;
}
@Override
public void read(byte[] bs) {
// ...
target.read(bs);
// ...
}
}
//源基类装饰器2
public class Decorator2 implements DecoratorTarget {
protected DecoratorTarget target;
public Decorator2(DecoratorTarget target) {
this.target = target;
}
@Override
public void read(byte[] bs) {
// ...
target.read(bs);
// ...
}
}
//源基类装饰器3
public class Decorator3 extends Decorator1 {
public Decorator3(DecoratorTarget target) {
super(target);
this.target = target;
}
@Override
public void read(byte[] bs) {
// ...
target.read(bs);
// ...
}
}

在main方法中,是这样呈现的,

1
DecoratorTarget target = new Decorator1(new Decorator3(new Decorator2(new DecoratorTargetSource())));

OK!认真讨论一下装饰器的特点,装饰器与被装饰者通常是一个家族的,也就是它们派生于同个Object外的祖宗,包括源、装饰器本身。

  • 为什么还要区分适配器与装饰器呢?

对比一下适配器,装饰器模式的DecoratorTargetSource几乎等同适配器模式的Adaptee2,它们的原理几乎是一样的,一个源头的接口需要修改或添加功能,则需要适配器或装饰器解决问题,不同的是不同适配器间往往没有血缘关系,而装饰器之间确实近亲关系甚至后代。

代码结构关系上,确实没什么必要区分开来,但它们的作用才能决定这一事情!
装饰器着重点在于,一个体系内的类的功能累加或修改,例如IO库。本来体系内的类已经有了很庞大复杂的继承关系,仅仅完善子类的功能而使用唯一的继承位置是浪费的,所以装饰器为体系的所有类提供了另一种继承方法,并且也为了类之间的相互适用。

适配器着重点在于,解决一个接口的不适用,也就是说它并不需要考虑继承体系内类的相互适用性,针对性强许多,倘若某个适配器确实还是需要一个适配器,你大可重写适配器(装饰器未必可以,你需要考虑体系其他类是否支持)。