
14. Template Method 本质:固定算法骨架
14.1 实现应用系统的前台和后台的登录控制
public class LoginModel {
private String loginId;
private String password;
public String getLoginId() {
return loginId;
}
public void setLoginId(String loginId) {
this.loginId = loginId;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
}
public abstract class LoginTemplate {
public final boolean login(LoginModel lm) {
LoginModel lmFromDb = this.findLoginUser(lm.getLoginId());
if (lmFromDb != null) {
String encryptPwd = this.encryptPwd(lm.getPassword());
lm.setPassword(encryptPwd);
return this.match(lm, lmFromDb);
}
return false;
}
public boolean match(LoginModel lm, LoginModel lmFromDb) {
if (lm.getLoginId().equals(lmFromDb.getLoginId()) && lm.getPassword().equals(lmFromDb.getPassword())) {
return true;
}
return false;
}
public String encryptPwd(String password) {
return password;
}
public abstract LoginModel findLoginUser(String loginId);
}
public class NormalLogin extends LoginTemplate{
@Override
public LoginModel findLoginUser(String loginId) {
LoginModel lm = new LoginModel();
lm.setLoginId(loginId);
lm.setPassword("normal");
return lm;
}
}
public class WorkerLogin extends LoginTemplate{
@Override
public LoginModel findLoginUser(String loginId) {
LoginModel lm = new LoginModel();
lm.setLoginId(loginId);
lm.setPassword("worker");
return lm;
}
public String encryptPwd(String pwd) {
System.out.println("Encrypt using MD5");
return pwd;
}
}
public class TemplateClient {
public static void main(String[] args) {
LoginModel lm = new LoginModel();
lm.setLoginId("admin");
lm.setPassword("worker");
LoginTemplate lt = new WorkerLogin();
LoginTemplate lt2 = new NormalLogin();
System.out.println("Login portal: " + lt2.login(lm));
System.out.println("Login console: " + lt.login(lm));
}
}
/**
* 封装进行登录控制所需要的数据,在公共数据的基础上,
* 添加具体模块需要的数据
*/
public class NormalLoginModel extends LoginModel{
/**
* 密码验证问题
*/
private String question;
/**
* 密码验证答案
*/
private String answer;
public String getQuestion() {
return question;
}
public void setQuestion(String question) {
this.question = question;
}
public String getAnswer() {
return answer;
}
public void setAnswer(String answer) {
this.answer = answer;
}
}
/**
* 普通用户登录控制加强版的逻辑处理
*/
public class NormalLogin2 extends LoginTemplate{
@Override
public LoginModel findLoginUser(String loginId) {
NormalLoginModel nlm = new NormalLoginModel();
nlm.setLoginId(loginId);
nlm.setPassword("normal");
nlm.setQuestion("question");
nlm.setAnswer("answer");
return nlm;
}
public boolean match(LoginModel lm, LoginModel lmFromDb) {
//这个方法需要覆盖,因为现在进行登录控制的时候,
//需要检测4个值是否正确,而不仅仅是缺省的2个
//先调用父类实现好的,检测编号和密码是否正确
boolean isSuperMatch = super.match(lm, lmFromDb);
if (isSuperMatch) {
//如果编号和密码正确,继续检查问题和答案是否正确
//先把数据转换成自己需要的数据
NormalLoginModel nlm = (NormalLoginModel)lm;
NormalLoginModel nlmFromDb = (NormalLoginModel)lmFromDb;
//检查问题和答案是否正确
if (nlm.getQuestion().equals(nlmFromDb.getQuestion()) && nlm.getAnswer().equals(nlmFromDb.getAnswer())) {
return true;
}
}
return false;
}
}
public class TemplateClient2 {
public static void main(String[] args) {
NormalLoginModel nlm = new NormalLoginModel();
nlm.setLoginId("user");
nlm.setPassword("normal");
nlm.setQuestion("question");
nlm.setAnswer("answer");
LoginTemplate lt3 = new NormalLogin2();
System.out.println("Login portal 2: " + lt3.login(nlm));
}
}
14.2 重构时把相同的代码抽取到父类中, 然后通过钩子函数约束其行为。
public abstract class HummerModel {
/*
* 首先,这个模型要能够被发动起来,别管是手摇发动,还是电力发动,反正
* 是要能够发动起来,那这个实现要在实现类里了
*/
protected abstract void start();
//能发动,那还要能停下来,那才是真本事
protected abstract void stop();
//喇叭会出声音,是滴滴叫,还是哔哔叫
protected abstract void alarm();
//引擎会轰隆隆的响,不响那是假的
protected abstract void engineBoom();
//那模型应该会跑吧,别管是人退的,还是电力驱动,总之要会跑
final public void run() {
//先发动汽车
this.start();
//引擎开始轰鸣
this.engineBoom();
//通过钩子方法约束行为:要让它叫的就是就叫,喇嘛不想让它响就不响
if(this.isAlarm()){
this.alarm();
}
//到达目的地就停车
this.stop();
}
//钩子方法,默认喇叭是会响的
protected boolean isAlarm(){
return true;
}
}
public class HummerH1Model extends HummerModel {
private boolean alarmFlag = true; //是否要响喇叭
@Override
protected void alarm() {
System.out.println("悍马H1鸣笛...");
}
@Override
protected void engineBoom() {
System.out.println("悍马H1引擎声音是这样在...");
}
@Override
protected void start() {
System.out.println("悍马H1发动...");
}
@Override
protected void stop() {
System.out.println("悍马H1停车...");
}
protected boolean isAlarm() {
return this.alarmFlag;
}
//要不要响喇叭,是有客户的来决定的
public void setAlarm(boolean isAlarm){
this.alarmFlag = isAlarm;
}
}
public class HummerH2Model extends HummerModel {
protected void alarm() {
System.out.println("悍马H2鸣笛...");
}
protected void engineBoom() {
System.out.println("悍马H2引擎声音是这样在...");
}
protected void start() {
System.out.println("悍马H2发动...");
}
protected void stop() {
System.out.println("悍马H2停车...");
}
//默认没有喇叭的
protected boolean isAlarm() {
return false;
}
}
public class Client {
public static void main(String[] args) throws IOException {
System.out.println("-------H1型号悍马--------");
System.out.println("H1型号的悍马是否需要喇叭声响?0-不需要 1-需要");
String type=(new BufferedReader(new InputStreamReader(System.in))).readLine();
HummerH1Model h1 = new HummerH1Model();
if(type.equals("0")){
h1.setAlarm(false);
}
h1.run();
System.out.println("\n-------H2型号悍马--------");
HummerH2Model h2 = new HummerH2Model();
h2.run();
}
}