定义
将类的接口转化为客户端希望的另外一个接口,使得原本由于接口不兼容而不能一起工作的类可以一起工作,别名Wrapper(包装器)。
适配器模式,最终改变一个已有对象的接口。
使用场景
当有那么个类,那么个对象,却不是我想要的接口类型,肿么办?不要方,用适配器模式。
java三要素:Target(目标)+Adaptee(待适配者)+Adapter(适配器)
- 类的适配器,实现Target接口,继承Adaptee类,把待适配类的API转化为目标接口的API。
- 对象适配器,实现Target接口,持有Adaptee对象,把待适配类的API转化为目标接口的API。
- 缺省适配器,abstract适配器(Adapter)实现Target接口,任意实现Adapter抽象类的均是Target接口类型,而不用实现全部Target接口方法。
个人理解
好比一个多用插排,将各种插头(Adaptee)通过插排(Adapter)适配到标准插口(Target)。
代码示例
interface Target {
void targetMethod1();
void targetMethod2();
}
class Adaptee {
public void targetMethod1() {
}
}
//类的适配器(继承,涉及类之间的关系,所以是类的适配器)
//java中没有多继承,使用单继承+实现接口,解决问题
class Adapter extends Adaptee implements Target {
@Override
public void targetMethod2() {
}
}
class Test{
public static void main(String[] args) {
Target target=new Adapter();//适配器Adapter将Adaptee类型适配成了Target目标接口类型
target.targetMethod1();
target.targetMethod2();
}
}
//对象适配器(类似一个包装类,将待适配类和目标类的API衔接,其中Adapter和Adaptee是委托关系,所以是对象的适配器)
//java中较为常见,注入待适配对象(Adaptee),实现目标接口即可。
class Adapter implements Target{
Adaptee adaptee;
public Adapter(Adaptee adaptee){
this.adaptee=adaptee;
}
@Override
public void targetMethod1() {
adaptee.targetMethod1();
}
@Override
public void targetMethod2() {
}
}
class Test{
public static void main(String[] args) {
Target target=new Adapter(new Adaptee());
target.targetMethod1();
target.targetMethod2();
}
}
//缺省适配器,任意Adapter实现类均是Target接口类型,而不行实现Target全部定义方法
//缺省适配的用意是为了方便建立一个不平庸的适配器类而提供的一种“平庸”实现,使得具体实现类免于被迫实现空的方法。
abstract class Adapter implements Target{
public void targetMethod1(){}//平庸化的实现,可空,可return null;
public void targetMethod2(){}
}
class Client1 extends Adapter{
@Override
public void targetMethod1(){
}
}
class Client2 extends Adapter{
@Override
public void targetMethod2(){
}
}
class Test{
public static void main(String[] args) {
new Client1().targetMethod1();
new Client2().targetMethod1();
}
}
类适配器和对象适配器
- 类适配器使用对象继承的方式,是静态的定义方式;而对象适配器使用对象组合的方式,是动态组合的方式。
- 类适配器可以重新定义Adaptee的部分行为,对象适配器适合新增新的行为。
- 类的适配器不需要额外引用得到Adaptee。
优缺点
- 优点
- 复用现存代码,应用于新接口
- 将Target和Adaptee解耦
- 一个适配器,可以同时对多个Adaptee适配成Target
- 适配时可以组合自定义功能,扩展性良好(类似装饰)
- 缺点
- 过多的依赖适配器,会导致对适配器修改较复杂
- 过多的适配器,会使得系统凌乱不清晰,如非必要,可以不使用
JDK中的适配器模式
如:java.util.Arrays
//将本身适配成list接口
public static <T> List<T> asList(T... a) {
return new ArrayList<>(a);
}
相关模式
装饰模式增加了对象的功能,但是不改变对象的接口,透明性较好,并且支持递归组合,是适配器模式虽然也为对象增加了功能,但是改变了接口,不支持递归组合。
代理模式,也是不改变接口的前提下,为一个对象的访问,提供了一个代理,使用场景不同。