一、適配器模式的應用場景
適配器模式(Adapter Pattern)是指將一個類的接口轉換成用戶期待的另一個接口,使原本接口不兼容的類可以一起工作,屬於構造設計模式。
適配器適用於以下幾種業務場景:
- 已經存在的類的方法和需求不匹配(方法結果相同或相似)的情況。
- 適配器模式不是軟件初始階段應該考慮的設計模式,是隨着軟件的開發,由於不同產品、不同廠家造成功能類似而接口不同的問題的解決方案,有點亡羊補牢的感覺。
二、重構第三方登錄自由適配的業務場景
將原來的單一支持用戶名和密碼登錄,擴展為可以支持微信和手機登錄。
創建統一返回結果ResultMsg:
@Data
public class ResultMsg {
private Integer code;
private String msg;
private Object data;
public ResultMsg(Integer code, String msg, Object data) {
this.code = code;
this.data = data;
this.msg = msg;
}
}
老系統登錄代碼如下:
public class SignInService {
public ResultMsg regist(String userName, String passWord) {
return new ResultMsg(200, "注冊成功", new Member());
}
public ResultMsg login(String userName, String passWord) {
return null;
}
}
為了遵循開閉原則,我們不修改老系統代碼,下面是Member類:
@Data
public class Member {
private String userName;
private String passWord;
private String mid;
private String info;
}
我們優雅的根據不同登錄方式創建不同的“Adapter”,首先創建LoginAdapter:
public interface LoginAdapter {
boolean support(Object adapter);
ResultMsg login(String id, Object adapter);
}
手機登錄:
public class LoginForTelAdapter implements LoginAdapter {
@Override
public boolean support(Object adapter) {
return adapter instanceof LoginForTelAdapter;
}
@Override
public ResultMsg login(String id, Object adapter) {
return null;
}
}
微信登錄:
public class LoginForWechatAdapter implements LoginAdapter {
@Override
public boolean support(Object adapter) {
return adapter instanceof LoginForWechatAdapter;
}
@Override
public ResultMsg login(String id, Object adapter) {
return null;
}
}
接着,創建第三方登錄兼容接口IPassportForThid:
public interface IPassportForThird {
ResultMsg loginForTel(String telephone, String code);
ResultMsg loginForWechat(String id);
ResultMsg loginForResist(String userName, String passWord);
}
實現兼容PassportForThirdAdapter:
public class PassportForThirdAdapter extends SignInService implements IPassportForThird {
@Override
public ResultMsg loginForTel(String telephone, String code) {
return null;
}
@Override
public ResultMsg loginForWechat(String id) {
return null;
}
@Override
public ResultMsg loginForResist(String userName, String passWord) {
super.regist(userName, passWord);
return super.login(userName, passWord);
}
//這里使用簡單工廠及策略模式
private ResultMsg procssLogin(String key, Class<? extends LoginAdapter> clazz) {
try {
LoginAdapter adapter = clazz.newInstance();
if (adapter.support(adapter)) {
return adapter.login(key, adapter);
}
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
}
前面每個適配器都加上了support()方法,用來判斷箭筒。support()方法的參數也是Object類型,而support()來自接口。適配器並不依賴接口,我們使用接口只是為了代碼規范。
三、適配器模式在源碼中的體現
Spring中的AOP中AdvisorAdapter類,它有三個實現:MethodBeforAdviceAdapter、AfterReturnningAdviceAdapter、ThrowsAdviceAdapter。
先看頂層接口AdviceAdapter的源代碼:
public interface AdvisorAdapter {
boolean supportsAdvice(Advice var1);
MethodInterceptor getInterceptor(Advisor var1);
}
再看MethodBeforAdviceAdapter:
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會根據不同的AOP配置來使用對應的“Advice”,與策略模式不同的是,一個方法可以同時擁有多個“Advice”。
四、適配器模式的優缺點
優點:
- 能提高類的透明性和復用性,現有的類會被復用但不需要改變。
- 目標類和適配器類解耦,可以提高程序的擴展性。
- 在很多業務場景中符合開閉原則。
缺點:
- 在適配器代碼編寫過程中需要進行全面考慮,可能會增加系統復雜度。
- 增加代碼閱讀難度,過多使用適配器會使系統代碼變得凌亂。

