(八)适配器模式详解 (一)

2014-11-24 10:41:11 · 作者: · 浏览: 4

作者:zuoxiaolong8810(左潇龙),转载请注明出处。

各位好,我们本次接着讨论第八个设计模式,适配器模式。

适配器模式从实现方式上分为两种,类适配器和对象适配器,这两种的区别在于实现方式上的不同,一种采用继承,一种采用组合的方式。

另外从使用目的上来说,也可以分为两种,特殊适配器和缺省适配器,这两种的区别在于使用目的上的不同,一种为了复用原有的代码并适配当前的接口,一种为了提供缺省的实现,避免子类需要实现不该实现的方法。

首先应该明白一点,适配器模式是补救措施,所以在系统设计过程中请忘掉这个设计模式,这个模式只是在你无可奈何时的补救方式。

那么我们什么时候使用这个模式呢?场景通常情况下是,系统中有一套完整的类结构,而我们需要利用其中某一个类的功能(通俗点说可以说是方法),但是我们的客户端只认识另外一个和这个类结构不相关的接口,这时候就是适配器模式发挥的时候了,我们可以将这个现有的类与我们的目标接口进行适配,最终获得一个双接口(这个双接口指的是即包括我们需要的接口,也包括原有的类的接口)的类。

接下来我们举一个例子,比如我们在观察者一章中就提到一个问题,就是说观察者模式的一个缺点,即如果一个现有的类没有实现Observer接口,那么我们就无法将这个类作为观察者加入到被观察者的观察者列表中了,这实在太遗憾了。

在这个问题中,我们需要得到一个Observer接口的类,但是又想用原有的类的功能,但是我们又改不了这个原来的类的代码,或者原来的类有一个完整的类体系,我们不希望破坏它,那么适配器模式就是你的不二之选了。

我们举个具体的例子,比如我们希望将HashMap这个类加到观察者列表里,在被观察者产生变化时,假设我们要清空整个MAP。但是现在加不进去啊,为什么呢?

因为Observable的观察者列表只认识Observer这个接口,它不认识HashMap,怎么办呢?

这种情况下,我们就可以使用类适配器的方式将我们的HashMap做点手脚,刚才已经说了,类适配器采用继承的方式,那么我们写出如下适配器。

[java]
public class HashMapObserverAdapter extends HashMap implements Observer{

public void update(Observable o, Object arg) {
//被观察者变化时,清空Map
super.clear();
}

}

public class HashMapObserverAdapter extends HashMap implements Observer{

public void update(Observable o, Object arg) {
//被观察者变化时,清空Map
super.clear();
}

} 即我们继承我们希望复用其功能的类,并且实现我们想适配的接口,在这里就是Observer,那么就会产生一个适配器,这个适配器具有原有类(即HashMap)的功能,又具有观察者接口,所以这个适配器现在可以加入到观察者列表了。

看,类适配器很简单吧?那么下面我们来看看对象适配器,刚才说了对象适配器是采用组合的方式实现。

为什么要采用组合呢?上面的方式不是很好吗?

究其根本,是因为JAVA单继承的原因,一个JAVA类只能有一个父类,所以当我们要适配的对象是两个类的时候,你怎么办呢?你难道要将两个类全部写到extends后面吗,如果你这么做了,那么编译器会表示它的不满的。

我们还是拿观察者模式那一章的例子来说(观察者模式比较惨,老要适配器模式擦屁股),比如我们现在有一个写好的类,假设就是个实体类吧。如下。

[java]
public class User extends BaseEntity{
private Integer id;
private String name;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}

public class User extends BaseEntity{
private Integer id;
private String name;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
} 看到了吧,我们的实体类大部分都是继承自BaseEntity的,那现在你怎么办吧,你要想具有被观察者的功能还要继承Observable类,你说你怎么继承吧。

你是不是想说,那我的User不继承BaseEntity不就完事了,我把BaseEntity里面的东西全部挪动到User类,或者我不继承Observable了,把Observable里面的东西全部挪到User类里面。

这并不是不行,但是这是个很大的隐患,比如我们项目到时候要针对BaseEntity的子类进行扫描,用来做一些事情,这时候如果User没继承BaseEntity,那么你就会遗漏掉这个类,这会破坏你的继承体系,付出太大了。

相反,如果你不继承Observable,那么你的User类看起来会非常杂乱,而且假设我现在不仅User类可以被观察了,我的Person类,Employee都能被观察了,你难道要把Observable的代码COPY三次到这三个类里面吗?

不要忘了刚才说的,适配器模式就是为了帮助我们复用代码的,这里使用适配器模式就可以帮我们复用Observable的代码或者说功能。

基于上面LZ的讨论,我们做出如下适配器,这里采用的对象适配器。

[java]
/我们继承User,组合Observable.
public class ObservableUser extends User{