寫在前面:
適配器模式(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交流電。
接下來,結合Spring AOP,看看適配器模式的實際運用。
切面編程(也可叫通知)大致分爲 前置通知(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 就是 動態代理技術的使用。而動態代理的使用依靠的就是 反射與適配器模式,這裏面說的可能過於絕對。但是,你懂的 就好啦。日後再聊。