适配器模式
适配(转换)的概念无处不在。。。。。。
适配,即咋不改变原有的实现的基础上,将原先不兼容的接口转换为兼容的接口。
动机(Motivation)
在软件系统中,由于应用环境的变化,常常需要将“一些现存的对象”放在新的环境中应用,但是新环境要求的接口是这些现存对象所不满足的。
如何应对着中国“迁移的变化”?如何既能利用现有对象的良好实现,同时又能满足新的应用环境所要求的接口?
意图(Intent)
将一个类的接口转换成现在希望的另一个接口。Adapter模式使得原本由于接口不兼容而不能再一起工作的那些类可以在一起工作。
从图上可看出,Adaptee类并没有sampleOperation2()方法,而客户端则期待这个方法,为使客户端能够使用Adaptedd类,提供一个中间环节,即类Adapter,把Adaptee的API与Target类的API衔接起来,Adapter与Adaptee是继承关系,这决定了这个适配模式是类的。
模式所涉及到的角色:
目标(Target)角色:这就是所期待得到的接口。注意,由于这里讨论的是类适配器模式,因此目标不可以是类。
源(Adaptee)角色:现有的适配的接口。
适配器(Adapter)角色:适配器类是本模式的核心,适配器把源接口转换成目标接口。显然,这一角色不可以是接口,而必须是类。
对象的适配器模式:
与类的适配器模式一样,对象的适配器模式吧适配的类的API转换成为目标类的API,与类的适配器模式不同的是,对象的适配器模式不是使用继承关系连接到Adaptee类,而是使用委派关系连接到Adaptee类,对象的适配器模式的静态结构如下:
从图上看出,Adaptee类并没有sampleOperation1()方法,而客户端则期待这个方法,为使客户端能够使用Adaptee类,需要提供一个包装(Wrapper)类Adapter.这个包装类包装了一个Adaptee的实例,从而此包装类能够把Adaptee的API与Target类的API衔接起来,Adapter与Adaptee是委派关系,这决定了这个适配模式是对象的。
对象适配器模式的效果:
一个适配器可以把多种不同的源适配到同一个目标,换言之,同一个适配器可以把源类和它的子类都适配到目标接口。
与类的适配器模式相比,要想置换源类的方法就不容易,如果一定要置换掉源类的一个或多个方法,就只好先做个一个源类的子类,将源类的方法置换掉,然后再把源类的子类当做真正的源进行适配。
虽然要想置换源类的方法不容易,但是要想增加一些新的方法则方便的很,而新增加的方法可同时适用于所有的源。
缺省适配器模式:
目标接口可以省略,此时,目标接口和源接口实际上是相同的,由于源是一个接口,而适配器类是一个类(抽象类),因此这种做法看似平庸而不平庸,它可以使客户不必实现不不需要的方法。
缺省适配模式的中心是一个缺省适配器类,这个类应当是抽象类,因为这个类不应当实例化,它的实例也没有用处。
但是去赫斯适配类所提供的方法却应当是具体的方法,而不是抽象的方法,因为按照模式的用意,这些方法之所以存在,就是为了提供默认实现,以便缺省适配类的具体子类可以按照需要只实现需要实现的方法,忽略不需要的实现的方法。
下面提供一个从Iterator到Enumeration的适配:
class Iteration implements Enumeration {
private Iterator it;
private Iteration(Iterator it) {
this.it = it;
}
public boolean hasMoreElements() {
return it.hasNext();
}
public Object nextElement() {
return it.next();
}
}