适配器模式(Adapter Pattern):将一个接口转换成客户希望的另一个接口,使接口不兼容的那些类可以一起工作,其别名为包装器(Wrapper)。适配器模式既可以作为类结构型模式,也可以作为对象结构型模式。 在适配器模式中,我们通过增加一个新的适配器类来解决接口不兼容的问题,使得原本没有任何关系的类可以协同工作。
根据适配器类与适配者类的关系不同,适配器模式可分为对象适配器和类适配器两种,在对象适配器模式中,适配器与适配者之间是关联关系;在类适配器模式中,适配器与适配者之间是继承(或实现)关系。
Target(目标抽象类):目标抽象类定义客户所需接口,可以是一个抽象类或接口,也可以是具体类。
Adapter(适配器类):适配器可以调用另一个接口,作为一个转换器,对Adaptee和Target进行适配,适配器类是适配器模式的核心,在对象适配器中,它通过继承Target并关联一个Adaptee对象使二者产生联系。
Adaptee(适配者类):适配者即被适配的角色,它定义了一个已经存在的接口,这个接口需要适配,适配者类一般是一个具体类,包含了客户希望使用的业务方法,在某些情况下可能没有适配者类的源代码。
我们国家的民用电都是 220V,日本是 110V,而我们的手机充电一般需要 5V,这时候要充电,就需要一个电压适配器,将 220V 或者 100V 的输入电压变换为 5V 输出。
定义输出电压的产品:
AC.java
public interface AC {
int output();
}
产品接口产生中国和日本的两种子产品
ACChina.java
public class ACChina implements AC {
@Override
public int output() {
return 220;
}
}
ACJapan.java
public class ACJapan implements AC {
@Override
public int output() {
return 110;
}
}
由于适配器只能适应一种产品,也就是说 中国和日本的两种电压 需要两个适配器来解决,so,又产生了电压适配器产品。
ACAdapter.java
public interface ACAdapter {
boolean support(AC ac); //是否支持此种电压适配
int outputDC5V(AC ac); //适配操作
}
中国适配电压:ChinaACAdapter.java
public class ChinaACAdapter implements ACAdapter {
@Override
public boolean support(AC ac) {
return ac.output() == 220;
}
@Override
public int outputDC5V(AC ac) {
return ac.output()/44;
}
}
日本适配电压:JapanACAdapter.java
public class JapanACAdapter implements ACAdapter {
@Override
public boolean support(AC ac) {
return ac.output() == 110;
}
@Override
public int outputDC5V(AC ac) {
return ac.output()/22;
}
}
适配操作:
@Test
public void tt(){
ACAdapter acAdapter = new ChinaACAdapter();
ACChina acChina = new ACChina();
if(acAdapter.support(acChina)){
System.out.println(acAdapter.outputDC5V(acChina));
}
}
success。
总结:
中国的电压使用中国的适配器,产生5V交流电。
切面编程(也可叫通知)大致分为 前置通知(BeforeAdvice),后置通知(AfterAdvice),环绕通知(ThrowsAdvice)。
这些通知的最底层产品是Advice。我们着重介绍介绍前置通知,其他的原理相同。
Advice.java
public interface Advice {
}
BeforeAdvice.java
public interface BeforeAdvice extends Advice {
}
MethodBeforeAdvice.java
public interface MethodBeforeAdvice extends BeforeAdvice {
void before(Method var1, Object[] var2, @Nullable Object var3) throws Throwable;
}
注意:在MethodBeforeAdvice里面就定义了前置通知的方法及参数,需要利用反射区调用。
接下来就到了 MethodBeforeAdvice的实现类也就是前置通知的具体操作了。
AspectJMethodBeforeAdvice.java
public class AspectJMethodBeforeAdvice extends AbstractAspectJAdvice implements MethodBeforeAdvice, Serializable {
public AspectJMethodBeforeAdvice(Method aspectJBeforeAdviceMethod, AspectJExpressionPointcut pointcut, AspectInstanceFactory aif) {
super(aspectJBeforeAdviceMethod, pointcut, aif);
}
public void before(Method method, Object[] args, @Nullable Object target) throws Throwable {
this.invokeAdviceMethod(this.getJoinPointMatch(), (Object)null, (Throwable)null);
}
public boolean isBeforeAdvice() {
return true;
}
public boolean isAfterAdvice() {
return false;
}
}
## 不知道你们注意到没有,他的判断方法包括 isBeforeAdvice 和 isAfterAdvice。
再然后,就是前置通知适配器了,因为要有一个适配器去适配拦截,然后再方法执行前,做一个通知。
MethodBeforeAdviceInterceptor.java
public class MethodBeforeAdviceInterceptor implements MethodInterceptor, BeforeAdvice, Serializable {
private final MethodBeforeAdvice advice;
public MethodBeforeAdviceInterceptor(MethodBeforeAdvice advice) {
Assert.notNull(advice, "Advice must not be null");
this.advice = advice;
}
public Object invoke(MethodInvocation mi) throws Throwable {
this.advice.before(mi.getMethod(), mi.getArguments(), mi.getThis());
return mi.proceed();
}
}
没错,就是一个拦截器,自定义注解了解一波,一般的注解都要利用反射+拦截器或者过滤器去做。可见,spring的做法是拦截器。当拦截到方法的上面有@before的时候,自然会调用我们这个前置通知适配器。他们帮我们做一些前置通知,以及目标方法的invoke()。然后返回结果。所以我理解的spring aop 就是 动态代理技术的使用。而动态代理的使用依靠的就是 反射与适配器模式,这里面说的可能过于绝对。但是,你懂的 就好啦。日后再聊。