本文節選自《設計模式就該這樣學》
1 使用類配接器重構第三方登錄自由適配
我們使用適配模式來實作一個實際的業務場景,解決實際問題,年紀稍微大一點的小伙伴一定經歷過這樣的程序,很早以前開發的老系統應該都有登錄介面,但是隨著業務的發展和社會的進步,單純地依賴用戶名密碼登錄顯然不能滿足用戶需求,現在,大部分系統都已經支持多種登錄方式,如QQ登錄、微信登錄、手機登錄、微博登錄等,同時保留用戶名密碼的登錄方式,雖然登錄形式豐富,但是登錄后的處理邏輯可以不必改,都是將登錄狀態保存到Session,遵循開閉原則,首先創建統一的回傳結果ResultMsg類,
/**
* Created by Tom.
*/
public class ResultMsg {
private int code;
private String msg;
private Object data;
public ResultMsg(int code, String msg, Object data) {
this.code = code;
this.msg = msg;
this.data = https://www.cnblogs.com/gupaoedu-tom/archive/2021/11/03/data;
}
public int getCode() {
return code;
}
public void setCode(int code) {
this.code = code;
}
public String getMsg() {
return msg;
}
public void setMsg(String msg) {
this.msg = msg;
}
public Object getData() {
return data;
}
public void setData(Object data) {
this.data = data;
}
}
假設在老系統中,處理登錄邏輯的代碼在PassportService類中,
public class PassportService {
/**
* 注冊方法
* @param username
* @param password
* @return
*/
public ResultMsg regist(String username,String password){
return new ResultMsg(200,"注冊成功",new Member());
}
/**
* 登錄方法
* @param username
* @param password
* @return
*/
public ResultMsg login(String username,String password){
return null;
}
}
為了遵循開閉原則,不修改老系統的代碼,下面開啟代碼重構之路,創建Member類,
/**
* Created by Tom.
*/
public class Member {
private String username;
private String password;
private String mid;
private String info;
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public String getMid() {
return mid;
}
public void setMid(String mid) {
this.mid = mid;
}
public String getInfo() {
return info;
}
public void setInfo(String info) {
this.info = info;
}
}
我們也不改動運行非常穩定的代碼,創建Target角色IPassportForThird介面,
public interface IPassportForThird {
ResultMsg loginForQQ(String openId);
ResultMsg loginForWechat(String openId);
ResultMsg loginForToken(String token);
ResultMsg loginForTelphone(String phone,String code);
}
創建Adapter角色實作兼容,創建一個新的類PassportForThirdAdapter,繼承原來的邏輯,
public class PassportForThirdAdapter extends PassportService implements IPassportForThird {
public ResultMsg loginForQQ(String openId) {
return loginForRegist(openId,null);
}
public ResultMsg loginForWechat(String openId) {
return loginForRegist(openId,null);
}
public ResultMsg loginForToken(String token) {
return loginForRegist(token,null);
}
public ResultMsg loginForTelphone(String phone, String code) {
return loginForRegist(phone,null);
}
private ResultMsg loginForRegist(String username,String password){
if(null == password){
password = "THIRD_EMPTY";
}
super.regist(username,password);
return super.login(username,password);
}
}
客戶端測驗代碼如下,
public static void main(String[] args) {
PassportForThirdAdapter adapter = new PassportForThirdAdapter();
adapter.login("tom","123456");
adapter.loginForQQ("sjooguwoersdfjhasjfsa");
adapter.loginForWechat("slfsjoljsdo8234ssdfs");
}
2 使用介面配接器優化代碼
通過這么一個簡單的適配動作,我們完成了代碼兼容,當然,代碼還可以更加優雅,根據不同的登錄方式,創建不同的Adapter,首先創建LoginAdapter介面,
public interface ILoginAdapter {
boolean support(Object object);
ResultMsg login(String id,Object adapter);
}
然后創建一個抽象類AbstractAdapter繼承PassportService原有的功能,同時實作ILoginAdapter介面,再分別實作不同的登錄適配,QQ登錄LoginForQQAdapter,
public class LoginForQQAdapter extends AbstractAdapter{
public boolean support(Object adapter) {
return adapter instanceof LoginForQQAdapter;
}
public ResultMsg login(String id, Object adapter) {
if(!support(adapter)){return null;}
//accesseToken
//time
return super.loginForRegist(id,null);
}
}
手機登錄LoginForTelAdapter,
public class LoginForTelAdapter extends AbstractAdapter{
public boolean support(Object adapter) {
return adapter instanceof LoginForTelAdapter;
}
public ResultMsg login(String id, Object adapter) {
return super.loginForRegist(id,null);
}
}
Token自動登錄LoginForTokenAdapter,
public class LoginForTokenAdapter extends AbstractAdapter {
public boolean support(Object adapter) {
return adapter instanceof LoginForTokenAdapter;
}
public ResultMsg login(String id, Object adapter) {
return super.loginForRegist(id,null);
}
}
微信登錄LoginForWechatAdapter,
public class LoginForWechatAdapter extends AbstractAdapter{
public boolean support(Object adapter) {
return adapter instanceof LoginForWechatAdapter;
}
public ResultMsg login(String id, Object adapter) {
return super.loginForRegist(id,null);
}
}
接著創建配接器PassportForThirdAdapter類,實作目標介面IPassportForThird完成兼容,
public class PassportForThirdAdapter implements IPassportForThird {
public ResultMsg loginForQQ(String openId) {
return processLogin(openId, LoginForQQAdapter.class);
}
public ResultMsg loginForWechat(String openId) {
return processLogin(openId, LoginForWechatAdapter.class);
}
public ResultMsg loginForToken(String token) {
return processLogin(token, LoginForTokenAdapter.class);
}
public ResultMsg loginForTelphone(String phone, String code) {
return processLogin(phone, LoginForTelAdapter.class);
}
private ResultMsg processLogin(String id,Class<? extends ILoginAdapter> clazz){
try {
ILoginAdapter adapter = clazz.newInstance();
if (adapter.support(adapter)){
return adapter.login(id,adapter);
}
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
}
客戶端測驗代碼如下,
public static void main(String[] args) {
IPassportForThird adapter = new PassportForThirdAdapter();
adapter.loginForQQ("sdfasdfasfasfas");
}
最后來看如下圖所示的類圖,

至此,在遵循開閉原則的前提下,我們完整地實作了一個兼容多平臺登錄的業務場景,當然,目前的這個設計并不完美,僅供參考,感興趣的小伙伴們可以繼續完善這段代碼,例如配接器類中的引數目前是設定為String,改為Object[]應該更合理,
學習到這里,相信小伙伴們會有一個疑問:配接器模式與策略模式好像區別不大?我要強調一下,配接器模式主要解決的是功能兼容問題,單場景適配可能不會和策略模式有對比,但復雜場景適配大家就很容易混淆,其實,大家有沒有發現一個細節,筆者給每個配接器類都加上了一個support()方法,用來判斷是否兼容,support()方法的引數型別也是Object,而support()來自介面,配接器類的實作邏輯并不依賴介面,完全可以將ILoginAdapter介面去掉,而加上介面,只是為了代碼規范,上面代碼可以說是策略模式、簡單工廠模式和配接器模式的綜合運用,
【推薦】Tom彈架構:收藏本文,相當于收藏一本“設計模式”的書

本文為“Tom彈架構”原創,轉載請注明出處,技術在于分享,我分享我快樂!
如果本文對您有幫助,歡迎關注和點贊;如果您有任何建議也可留言評論或私信,您的支持是我堅持創作的動力,關注微信公眾號『 Tom彈架構 』可獲取更多技術干貨!
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/346874.html
標籤:其他
上一篇:Python入門(上)
