适配器模式(Adapter Pattern)
属于结构型模式
的一种,把一个类的接口变成客户端所期待的另一种接口,从而使原本接口不匹配而无法一起工作的两个类能够在一起工作…
适配器模式
1 概述
当你想使用一个已经存在的类,而它的接口不符合你的需求,或者你想创建一个可重用的类(与不兼容接口无关的类),这时候可以考虑使用适配器模式
。同时它也是一种包装模式,它与装饰模式
同样具有包装的功能。
适配器模式有两种:类适配器、对象适配器、接口适配器
前二者在实现上有些许区别,作用一样,第三个接口适配器差别较大。
2 类适配器
原理:通过继承来实现适配器功能。
当我们要访问的接口A中没有我们想要的方法 ,却在另一个接口B中发现了合适的方法,我们又不能改变访问接口A,在这种情况下,我们可以定义一个适配器p来进行中转,这个适配器p要实现我们访问的接口A,这样我们就能继续访问当前接口A中的方法(虽然它目前不是我们的菜),然后再继承接口B的实现类BB,这样我们可以在适配器P中访问接口B的方法了,这时我们在适配器P中的接口A方法中直接引用BB中的合适方法,这样就完成了一个简单的类适配器。
我们以ps2与usb的转接为例
ps2接口:Ps2
1 | public interface Ps2 { |
USB接口:Usb
1 | public interface Usb { |
USB接口实现类:Usber
1 | public class Usber implements Usb { |
适配器:Adapter
1 | public class Adapter extends Usber implements Ps2 { |
测试方法:Clienter
1 | public class Clienter { |
显示结果:
1 | USB口 |
实例讲解:
我手中有个ps2插头的设备,但是主机上只有usb插头的插口,怎么办呢?弄个转换器,将ps2插头转换成为USB插头就可以使用了。
接口Ps2:描述ps2接口格式
接口Usb:描述USB接口格式
类Usber:是接口Usb的实现类,是具体的USB接口格式
Adapter:用于将ps2接口格式转换成为USB接口格式
3 对象适配器模式
原理:通过组合来实现适配器功能。
当我们要访问的接口A中没有我们想要的方法 ,却在另一个接口B中发现了合适的方法,我们又不能改变访问接口A,在这种情况下,我们可以定义一个适配器p来进行中转,这个适配器p要实现我们访问的接口A,这样我们就能继续访问当前接口A中的方法(虽然它目前不是我们的菜),然后在适配器P中定义私有变量C(对象)(B接口指向变量名),再定义一个带参数的构造器用来为对象C赋值,再在A接口的方法实现中使用对象C调用其来源于B接口的方法。
我们仍然以ps2与usb的转接为例
ps2接口:Ps2
1 | public interface Ps2 { |
USB接口:Usb
1 | public interface Usb { |
USB接口实现类:Usber
1 | public class Usber implements Usb { |
适配器:Adapter
1 | public class Adapter implements Ps2 { |
测试类:Clienter
1 | public class Clienter { |
结果显示:
1 | USB口 |
4 接口适配器模式
原理:通过抽象类来实现适配,这种适配稍别于上面所述的适配。
当存在这样一个接口,其中定义了N多的方法,而我们现在却只想使用其中的一个到几个方法,如果我们直接实现接口,那么我们要对所有的方法进行实现,哪怕我们仅仅是对不需要的方法进行置空(只写一对大括号,不做具体方法实现)也会导致这个类变得臃肿,调用也不方便,这时我们可以使用一个抽象类作为中间件,即适配器,用这个抽象类实现接口,而在抽象类中所有的方法都进行置空,那么我们在创建抽象类的继承类,而且重写我们需要使用的那几个方法即可。
目标接口:A
1 | public interface A { |
适配器:Adapter
1 | public abstract class Adapter implements A { |
实现类:Ashili
1 | public class Ashili extends Adapter { |
测试类:Clienter
1 | public class Clienter { |
5 JDK 中的适配器使用
使用适配器模式的类
1 | java.util.Arrays#asList() |
Java I/O 库大量使用了适配器模式,如 ByteArrayInputStream
是一个适配器类,它继承了 InputStream
的接口,并且封装了一个 byte 数组。换言之,它将一个 byte 数组的接口适配成 InputStream 流处理器的接口。
在 OutputStream
类型中,所有的原始流处理器都是适配器类。ByteArrayOutputStream
继承了 OutputStream
类型,同时持有一个对 byte 数组的引用。它一个 byte 数组的接口适配成 OutputString 类型的接口,因此也是一个对象形式的适配器模式的应用。
FileOutputStream
继承了 OutputStream
类型,同时持有一个对 FileDiscriptor
对象的引用。这是一个将 FileDiscriptor
接口适配成 OutputStream
接口形式的对象型适配器模式。
Reader
类型的原始流处理器都是适配器模式的应用。StringReader
是一个适配器类,StringReader
类继承了 Reader
类型,持有一个对 String 对象的引用。它将 String 的接口适配成 Reader
类型的接口。
6 Spring 中使用适配器模式
在 Spring 的 AOP 里通过使用的 Advice(通知)来增强被代理类的功能。Spring 实现这一 AOP 功能的原理就使用代理模式(1、JDK 动态代理。2、CGLib 字节码生成技术代理。)对类进行方法级别的切面增强,即,生成被代理类的代理类,并在代理类的方法前,设置拦截器,通过执行拦截器中的内容增强了代理方法的功能,实现的面向切面编程。
Advice(通知)的类型有:BeforeAdvice、AfterReturningAdvice、ThrowSadvice 等。每个类型 Advice(通知)都有对应的拦截器,MethodBeforeAdviceInterceptor、AfterReturningAdviceInterceptor、ThrowsAdviceInterceptor。Spring 需要将每个 Advice(通知)都封装成对应的拦截器类型,返回给容器,所以需要使用适配器模式对 Advice 进行转换
1 | public interface MethodBeforeAdvice extends BeforeAdvice { |