版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/u012099869/article/details/78689257
主要内容参考自《研磨设计模式》
一、模式定义
定义一个操作中的算法的骨架,而将一些步骤延迟到子类中。模板方法使得子类可以不改变一个算法的结构即可重定义该算法的某些特定步骤。
二、模式结构
三、代码示例
场景:有普通登录、管理员登录两种登录方式,其中登录判断的逻辑一致,根据用户名获取登录密码不同。
根据模板方法模式设计如下:
登录模板类: 定义登录逻辑,以及相关的原语操作、钩子操作
普通登录类: 继承登录模板类,并实现获取用户密码接口
管理员登录类:继承登录模板类,并实现获取登录密码接口,重写加密算法
登录模板类:
package com.kascend.test.login;
/**
* 登录模板类
*
* @author wengliemiao
*/
public abstract class LoginTemplate {
/**
* 登录流程判断
*
* @param username 用户名
* @param password 密码
* @return 是否成功登录
*/
public final boolean login(String username, String password) {
String pwd = this.getPwd(username);
pwd = encrypt(pwd);
return this.match(password, pwd);
}
public abstract String getPwd(String userName);
/**
* 加密密码,子类有不同加密算法可覆盖
*
* @param pwd 密码
* @return 加密后的密码
*/
public String encrypt(String pwd) {
return pwd;
}
/**
* 判断密码是否匹配
*
* @param password 用户输入的密码
* @param dbPwd 数据库存储的密码
* @return 是否匹配
*/
public boolean match(String password, String dbPwd) {
return password.equals(dbPwd);
}
}
普通登录类:
package com.kascend.test.login;
/**
* 普通登录方式类
*
* @author wengliemiao
*/
public class NormalLogin extends LoginTemplate {
@Override
public String getPwd(String userName) {
return "normalPwd";
}
}
管理员登录类:
package com.kascend.test.login;
/**
* 管理员登录类
*
* @author wengliemiao
*/
public class AdminLogin extends LoginTemplate {
@Override
public String getPwd(String userName) {
return "adminPwd";
}
@Override
public String encrypt(String pwd) {
System.out.println("admin md5 encrypt...");
return "md5AdminPwd";
}
}
登录测试类:
package com.kascend.test.login;
/**
* 不同登录方式测试类
*
* @author wengliemiao
*/
public class LoginTest {
public static void main(String[] args) {
LoginTemplate normalLogin = new NormalLogin();
boolean isNormal = normalLogin.login("wlmmm", "normalPwd");
System.out.println("普通登录: " + isNormal);
LoginTemplate adminLogin = new AdminLogin();
boolean isAdmin = adminLogin.login("wlmmm", "md5AdminPwd");
System.out.println("管理员登录: " + isAdmin);
}
}
输出结果为:
四、Java 回调
通过回调在接口中定义的方法,调用到具体的实现类中的方法。其本质同样是利用 Java 的动态绑定技术,属于模板方法模式的变形实现。在这种实现中,可使用匿名内部类来实现回调方法。
如jdk中的 Collections.sort(list, comparator):
Collections.sort(null, new Comparator<Object>() {
@Override
public int compare(Object o1, Object o2) {
return 0;
}
});
继承、Java 回调两种方式的优缺点:
- 使用继承方式,抽象方法和具体实现的关系是在编译期间静态决定,是类级的关系;使用 Java 回调,关系是在运行期间动态决定,是对象级的关系
- 相对而言,使用回调机制会更灵活。因为 Java 的继承是单继承,对于子类而言,不能再继承其他对象,而回调基于接口
- 相对而言,使用继承方式更简单点。因为父类提供了实现方法,子类如果不想扩展,则不重写即可。但使用回调机制,则必须实现所有的接口,而不管是否需要扩展。
五、模式优缺点和使用时机
优缺点:
- 实现代码复用
- 算法骨架不易升级
使用时机:
- 需要固定算法骨架,定义不变的部分,并将可变的行为留给子类实现
- 各子类中有公共的行为,应抽取出来,其中在一个公共类中去实现
- 需要控制子类扩展的情况。
相关知识点:
抽象类与接口