适配器模式(Adapter Pattern):将一个接口转换成客户希望的另一个接口,使接口不兼容的那些类可以一起工作,其别名为包装器(Wrapper)。适配器模式既可以作为类结构型模式,也可以作为对象结构型模式。
- 我的技术博客:https://nezha.github.io,https://nezhaxiaozi.coding.me
- 我的简书地址:https://www.jianshu.com/u/a5153fbb0434
- 本文的demo地址:DesignPatterns/AdapterPattern
适配器模式主要有两种模式:1.类适配器模式
;2.对象适配器模式
其中:
类适配器模式
主要使用的是继承
的思想;对象适配器模式
使用的组合引用
的思想。
不管哪种模式下,适配者模式的主要组成部分有三部分:
目标(Target)角色
:这就是所期待得到的接口。注意,由于这里讨论的是类适配器模式,因此目标不可以是类。源(Adaptee)角色
:有目标(Target)角色
的部分功能,但是还是不满足或者是源(Adaptee)直接不满足目标的接口功能,需要配置它。适配器(Adapter)角色
:适配器类是本模式的核心。适配器把源接口转换成目标接口。显然,这一叫色不可以是接口,而必须是具体类。
UML图解读
下图是类适配器的UML图,其中Target
是目标接口,含有两个待实现的方法;Adaptee
是源接口(需要被改造或者扩展),它有一个实现方法operateA
;然后适配器Adapter
类implements
了Target
接口,并且集成了Adaptee
源接口。所以通过适配器类就可以有完整的Target
接口功能了。最后在客户端使用中就可以将Target
接口的实例化指向Adapter
类了。
还有一种比较常见的适配器就是对象适配器了。Target
接口和Adaptee
源接口都没有变化;最大的变化还是适配器类了,首先Adapter
类放弃使用继承而是使用引用的方式来引入源接口,然后Adaptee
的实例对象也是通过构造方法延迟注入了;最后还是需要实现Target
接口的两个方法,只不过operateA
是通过Adaptee
源的实例对象执行的。
类适配器
/**
* @Description: 目标接口 <br>
*/
public interface Target {
//1.operateA是在源(Adaptee)中有实现的
void operateA();
//2.operateB在源(Adaptee)中没有实现,需要使用适配器
void operateB();
}
/**
* @Description: 源(Adaptee)角色 <br>
*/
public class Adaptee {
public void operateA(){
System.out.println("我是已经实现的operateA");
}
}
/**
* @Description: 适配器(Adapter)角色 <br>
*/
public class Adapter extends Adaptee implements Target {
//其中operateA通过继承的方式已经集成到Adapter中了
@Override
public void operateB() {
System.out.println("我是通过适配器实现的operateB");
}
}
/**
* @Description: 类适配器模式 <br>
*/
public class AdapterClient {
public static void main(String[] args) {
//目标Target是通过适配器Adapter获得的
Target adapter = new Adapter();
adapter.operateA();
adapter.operateB();
}
}
结果:
我是已经实现的operateA
我是通过适配器实现的operateB
对象适配器
public interface Target {
//1.operateA是在源(Adaptee)中有实现的
void operateA();
//2.operateB在源(Adaptee)中没有实现,需要使用适配器
void operateB();
}
public class Adaptee {
public void operateA(){
System.out.println("在源(Adaptee)中实现的operateA");
}
}
public class Adapter implements Target {
private Adaptee adaptee;
public Adapter(Adaptee adaptee){
this.adaptee = adaptee;
}
@Override
public void operateA() {
//通过传入的源对象实现operateA
this.adaptee.operateA();
}
@Override
public void operateB() {
System.out.println("我是通过适配器的实现接口实现的operateB");
}
}
public class AdapterClient {
public static void main(String[] args) {
//1.实例化源 Adaptee
Adaptee adaptee = new Adaptee();
//2.创建适配者对象,并且传入源
Target target = new Adapter(adaptee);
target.operateA();
target.operateB();
}
}
结果:
在源(Adaptee)中实现的operateA
我是通过适配器的实现接口实现的operateB
应用场景
Spring
中也有适配器模式的典型应用。
在 Spring
的 AOP
中,使用的 Advice
(通知)来增强被代理类的功能。Spring
实现这一 AOP
功能的原理就使用代理模式(1、JDK动态代理。2、CGLib字节码生成技术代理。
)对类进行方法级别的切面增强,即,生成被代理类的代理类, 并在代理类的方法前,设置拦截器,通过执行拦截器的内容增强了代理方法的功能,实现的面向切面编程。
Advice
(通知)的类型有:MethodBeforeAdvice
、AfterReturningAdvice
、ThrowsAdvice
的。
在每个类型Advice
(通知)都有对应的拦截器,MethodBeforeAdviceInterceptor
、AfterReturningAdviceInterceptor
、ThrowsAdviceInterceptor
。
Spring
需要将每个Advice
(通知)都封装成对应的拦截器类型,返回给容器,所以需要使用适配器模式对Advice
进行转换。下面我们看看具体的代码。
MethodBeforeAdvice类:Adaptee
Adapter类接口:Target
MethodBeforeAdviceAdapter类,Adapter
DefaultAdvisorAdapterRegistry类,Client
public class DefaultAdvisorAdapterRegistry implements AdvisorAdapterRegistry, Serializable {
private final List<AdvisorAdapter> adapters = new ArrayList<AdvisorAdapter>(3);
/**
* Create a new DefaultAdvisorAdapterRegistry, registering well-known adapters.
*/
public DefaultAdvisorAdapterRegistry() {//这里注册了适配器
registerAdvisorAdapter(new MethodBeforeAdviceAdapter());
registerAdvisorAdapter(new AfterReturningAdviceAdapter());
registerAdvisorAdapter(new ThrowsAdviceAdapter());
}
public Advisor wrap(Object adviceObject) throws UnknownAdviceTypeException {
if (adviceObject instanceof Advisor) {
return (Advisor) adviceObject;
}
if (!(adviceObject instanceof Advice)) {
throw new UnknownAdviceTypeException(adviceObject);
}
Advice advice = (Advice) adviceObject;
if (advice instanceof MethodInterceptor) {
// So well-known it doesn't even need an adapter.
return new DefaultPointcutAdvisor(advice);
}
for (AdvisorAdapter adapter : this.adapters) {
// Check that it is supported.
if (adapter.supportsAdvice(advice)) {//这里调用了适配器的方法
return new DefaultPointcutAdvisor(advice);
}
}
throw new UnknownAdviceTypeException(advice);
}
public MethodInterceptor[] getInterceptors(Advisor advisor) throws UnknownAdviceTypeException {
List<MethodInterceptor> interceptors = new ArrayList<MethodInterceptor>(3);
Advice advice = advisor.getAdvice();
if (advice instanceof MethodInterceptor) {
interceptors.add((MethodInterceptor) advice);
}
for (AdvisorAdapter adapter : this.adapters) {
if (adapter.supportsAdvice(advice)) {//这里调用了适配器的方法
interceptors.add(adapter.getInterceptor(advisor));
}
}
if (interceptors.isEmpty()) {
throw new UnknownAdviceTypeException(advisor.getAdvice());
}
return interceptors.toArray(new MethodInterceptor[interceptors.size()]);
}
public void registerAdvisorAdapter(AdvisorAdapter adapter) {
this.adapters.add(adapter);
}
}