共计 5339 个字符,预计需要花费 14 分钟才能阅读完成。
本文节选自《设计模式就该这样学》
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 = 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 弹架构』可获取更多技术干货!