设计模式之模板方法模式

前言

模板方法模式(Template Method Pattern),定义一个操作中的算法骨架,而将一些实现步骤延迟到子类当中。模板方法使得子类可以在不改变算法结构的情况下,重新定义算法中的某些步骤,是代码复用的一项基本的技术。

场景案例

在调用第三方开放平台拉取用户信息的时候(例如:qq,sina,wechat等第三方登录),都是采用auth2.0授权流程,具体步骤如下:

  • 第一步:系统根据第三方登录类型(qq,sina,wechat等),获取对于的appKey和appSecret等信息(一般以key,value的形式存于配置文件中);
  • 第二步:根据第三方平台分配的appKey,appSecret及用户授权信息等,获取授权码authToken;
  • 第三步:根据返回的授权码authToken(仅能使用一次),获取访问码accessToken;
  • 第四步:根据accessToken获取用户的相关信息(例如:用户唯一openId,用户头像,昵称等);

很明显,以上代码执行步骤具有严格的顺序一致性而且每一步都依赖上一步的执行结果,完全符合模板方法模式的思想。

场景设计

类设计图(模板模式)

示例代码

ParamChain类:
public class ParamChain {
private String agent = null;//终端类型:android, ios
private String from = null;//qq,sina,wechat等
private String appKey = null;
private String appSecret = null;
private String authToken = null;
private String accessToken = null;
//setter,getter实现忽略
}

UserInfo类:
public class UserInfo {
private String openId = null;
private String icon = null;
private String nickName = null;
//setter,getter实现忽略
}

ThirdUserInfo核心接口:
public interface ThirdUserInfo {
//模板方法
UserInfo getThirdUserInfo(ParamChain paramChain);
}

AbstractThirdAuth核心抽象类:
public abstract class AbstractThirdAuth implements ThirdUserInfo {
//模板方法定义成final,防止子类重写,修改算法骨架(模板方法模式关键)
public final UserInfo getThirdUserInfo(ParamChain paramChain) {
getAppKeyAndSecret(paramChain);
getAuthToken(paramChain);
getAccessToken(paramChain);
return getUserInfo(paramChain);
}

//步骤一
protected void getAppKeyAndSecret(ParamChain paramChain) {
//根据agent和from查询配置文件,获取appKey,appSecret信息;
paramChain.setAppKey("xxx");
paramChain.setAppSecret("xxx");
}

//步骤二
protected void getAuthToken(ParamChain paramChain) {
//空方法体,由子类实现具体逻辑
}

//步骤三
protected void getAccessToken(ParamChain paramChain) {
//空方法体,由子类实现具体逻辑
}

//步骤四
protected UserInfo getUserInfo(ParamChain paramChain) {
UserInfo userInfo = new UserInfo();
//由子类实现具体逻辑
return userInfo;
}
}

QqThirdAuth 具体实现类:
public class QqThirdAuth extends AbstractThirdAuth {
protected void getAuthToken(ParamChain paramChain) {
String appkey = paramChain.getAppKey();
String appSecret = paramChain.getAppSecret();
//执行qq第三方登录获取authToken的逻辑
paramChain.setAuthToken("xxx");
}

protected void getAccessToken(ParamChain paramChain) {
String authToken = paramChain.getAuthToken();
//执行qq第三方登录获取accessToken的逻辑
paramChain.setAccessToken("xxx");
}

protected UserInfo getUserInfo(ParamChain paramChain) {
UserInfo userInfo = super.getUserInfo(paramChain);
String accessToken = paramChain.getAccessToken();
//执行qq第三方登录获取用户信息的逻辑
userInfo.setOpenId("xxx");
userInfo.setIcon("xxx");
userInfo.setNickName("xxx");
return userInfo;
}
}

SinaThirdAuth 和 WechatThirdAuth实现的具体思路同上。

ThirdAuthFactory三方授权工厂类:
public abstract class ThirdAuthFactory {
public static ThirdUserInfo createThirdAuth(String from) {
if("qq".equals(from)){
return new QqThirdAuth();
} else if("sina".equals(from)){
return new SinaThirdAuth();
} else if("wechat".equals(from)){
return new WechatThirdAuth();
} esle {
return null;
}
}
}

client 测试:
public class Client {
public static void main(String[] args){
ThirdUserInfo thirdAuth = ThirdAuthFactory.createThirdAuth("qq");
ParamChain paramChain = new ParamChain();
paramChain.setAgent("ios");
paramChain.setFrom("qq");
// 调用模板方法
UserInfo userInfo = thirdAuth.getThirdUserInfo();
//经过重构,client的耦合度更低,代码更简洁
System.out.println(userInfo.toString());
}
}