模板方法模式
1.什么是模版方法?
1.定义了一个操作中的算法的骨架,而将部分步骤的实现在子类中完成。 模板方法模式使得子类可以不改变一个算法的结构即可重定义该算法的某些特定步骤。
2.模板方法模式是所有模式中最为常见的几个模式之一,是基于继承的代码复用的基本技术,没有关联关系。 因此,在模板方法模式的类结构图中,只有继承关系。
2.核心设计要点:
AbstractClass : 抽象类,定义并实现一个模板方法。这个模板方法定义了算法的骨架,而逻辑的组成 步骤在相应的抽象操作中,推迟到子类去实现
ConcreteClass : 实现父类所定义的一个或多个抽象方法。
3.模板方法模式的优缺点及使用场景
1.优点: 模板方法模式通过把不变的行为搬移到超类,去除了子类中的重复代码。子类实现算法的某些细节,有助于算法的扩展。通过一个父类调用子类实现的操作,通过子类扩展增加新的行为,符合“开放-封闭原则”。
2.缺点 “每个不同的实现都需要定义一个子类,这会导致类的个数的增加,设计更加抽象。
3.适用场景 :在某些类的算法中,用了相同的方法,造成代码的重复。控制子类扩展,子类必须遵守算法规则。
4.案例(聚合登录)
1.创建模板方法抽象类
package com.xhs.pattern.template;
import lombok.extern.slf4j.Slf4j;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Component;
import java.util.Map;
/**
* @desc: 登录模板
* @author: xhs
* @date: 2021/7/23 10:11
* @version: JDK 1.8
*/
@Slf4j
@Component
public abstract class AbstractLoginTemplate {
/**
* 登录成功的状态码
*/
private static String LOGIN_CODE = "200";
/**
* 登录方法
*
* @return
*/
public String login() {
// 1.登录
Map<String, String> login = myLogin();
// 2.记录登录日志
loginLog(login);
// 3.发送登录通知
String loginCode = login.get("loginCode");
if (!LOGIN_CODE.equals(loginCode)) {
// 登录失败
return loginFile();
}
return loginNotice(login);
}
/**
* 登录
*
* @return
*/
protected abstract Map<String, String> myLogin();
/**
* 异步记录登录日志
*
* @param login
*/
@Async
protected void loginLog(Map<String, String> login) {
log.info(">>>>>第二步 记录登录日志.....loginLog()");
}
/**
* 3.发送登录通知
*
* @param login
* @return
*/
protected abstract String loginNotice(Map<String, String> login);
/**
* 登录失败
*
* @return
*/
protected abstract String loginFile();
}
2.创建具体实现模板
package com.xhs.pattern.template.impl;
import com.xhs.pattern.template.AbstractLoginTemplate;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import java.util.HashMap;
import java.util.Map;
/**
* @desc: 微信登录
* @author: xhs
* @date: 2021/7/23 10:35
* @version: JDK 1.8
*/
@Slf4j
@Component
public class WeChartTemplateImpl extends AbstractLoginTemplate {
@Override
protected Map<String, String> myLogin() {
// 假设以下为微信登录返回报文
log.info(">>>>>第一步 微信登录.....myLogin()");
Map<String, String> weChartLogin = new HashMap<>(16);
weChartLogin.put("weChartName", "test");
weChartLogin.put("weCharCode", "12345678");
// 登录状态为1表示为成功....
weChartLogin.put("loginStatus", "1");
// 自定义解析报文是否成功的状态码 200 为成功..
weChartLogin.put("loginCode", "200");
return weChartLogin;
}
@Override
protected String loginNotice(Map<String, String> login) {
log.info(">>>>>第三步 发送微信登录通知.....loginNotice()");
return "微信登录成功";
}
@Override
protected String loginFile() {
log.info(">>>>>微信登录失败.....loginFile()");
return "微信登录失败";
}
}
package com.xhs.pattern.template.impl;
import com.xhs.pattern.template.AbstractLoginTemplate;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import java.util.HashMap;
import java.util.Map;
/**
* @desc: QQ登录
* @author: xhs
* @date: 2021/7/23 10:20
* @version: JDK 1.8
*/
@Slf4j
@Component
public class QqLoginTemplateImpl extends AbstractLoginTemplate {
@Override
protected Map<String, String> myLogin() {
// 假设以下为QQ登录返回报文
log.info(">>>>>第一步 QQ登录.....myLogin()");
Map<String, String> login = new HashMap<>(16);
login.put("userName", "test");
login.put("QQCode", "12345678");
// 登录状态为1表示为成功....
login.put("loginStatus", "1");
// 自定义解析报文是否成功的状态码 200 为成功..
login.put("loginCode", "200");
return login;
}
@Override
protected String loginNotice(Map<String, String> login) {
log.info(">>>>>第三步 发送QQ登录通知.....loginNotice()");
return "QQ登录成功";
}
@Override
protected String loginFile() {
log.info(">>>>>QQ登录失败.....loginFile()");
return "QQ登录失败";
}
}
3.使用工厂模式获取模版
package com.xhs.pattern.template.factory;
import com.xhs.pattern.template.AbstractLoginTemplate;
import com.xhs.pattern.utils.SpringUtils;
/**
* @desc: 模板方法的工厂
* @author: xhs
* @date: 2021/7/23 10:44
* @version: JDK 1.8
*/
public class TemplateFactory {
/**
* 使用工厂方法获取模板
* @param templateId
* @return
*/
public static AbstractLoginTemplate getLoginTemplate(String templateId) {
AbstractLoginTemplate payCallbackTemplate = (AbstractLoginTemplate) SpringUtils.getBean(templateId);
return payCallbackTemplate;
}
}
4.创建Controller
package com.xhs.pattern.template.controller;
import com.xhs.pattern.dto.request.LoginTemplateRequest;
import com.xhs.pattern.template.AbstractLoginTemplate;
import com.xhs.pattern.template.factory.TemplateFactory;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;
/**
* @desc: 模板方法登录
* @author: xhs
* @date: 2021/7/23 10:39
* @version: JDK 1.8
*/
@RestController
public class LoginTemplateController {
@PostMapping("/loginTemplate")
public String loginTemplate(@RequestBody LoginTemplateRequest loginTemplateRequest) {
AbstractLoginTemplate loginTemplate = TemplateFactory.getLoginTemplate(loginTemplateRequest.getTemplateId());
String login = loginTemplate.login();
return login;
}
}
用到的SpringUtils在源码中获取
5.测试模板方法
localhost:1114/loginTemplate