行为模式——模板方法模式
一、定义
模板方法模式是一种行为设计模式, 它在超类中定义了一个算法的框架, 允许子类在不修改结构的情况下重写算法的特定步骤。
二、问题
假设现在你要做一个登录系统,每个角色(普通用户、管理员、超级管理员)的登录功能相似但又有所差别,那么我们会如何设计这个系统呢?
三、解决方案
我们可以设计一个抽象的模板方法,它实现一些每个具体类重复的代码(比如从数据库中查询用户名和密码),每个具体类中再实现各自不同的功能(比如 不同角色密码的加密方式不同)
四、代码实现
1、抽象类 (AbstractClass) 会声明作为算法步骤的方法, 以及依次调用它们的实际模板方法。 算法步骤可以被声明为 抽象类型, 也可以提供一些默认实现。
package com.atmae.templateMethod;
import java.util.List;
import java.util.Objects;
/**
* @Author: Mae
* @Date: 2022/4/14
* @Time: 8:08
* @Description:
*/
public abstract class Login {
/**
* 模板方法 定义为final 防止篡改
*/
public final void templateMethod() {
List<String> list = forwardPage();
boolean back = back(list);
String dig = action(back);
System.out.println(dig);
}
/**
* 前台页面
*/
public abstract List<String> forwardPage();
/**
* 后台
*
* @return
*/
public abstract boolean back(List<String> list);
/**
* 前台action
*
* @return
*/
public abstract String action(boolean back);
}
2、
管理员
package com.atmae.templateMethod;
import java.util.ArrayList;
import java.util.List;
import java.util.Scanner;
/**
* @Author: Mae
* @Date: 2022/4/14
* @Time: 8:08
* @Description: 管理员
*/
public class AdminLogin extends Login {
@Override
public List<String> forwardPage() {
//输入用户名和密码
String username = null, password = null;
Scanner scanner = new Scanner(System.in);
username=scanner.next();
password=scanner.next();
//密码加密
String newPassword = "3306" + password + "8080%@!#";
List<String> list = new ArrayList<>();
list.add(username);
list.add(newPassword);
return list;
}
@Override
public boolean back(List<String> list) {
//从后台数据库获取加密后的算法密码
//模拟:
String passwordByDatabase = "33061234568080%@!#";
return list.get(1).equals(passwordByDatabase);
}
@Override
public String action(boolean back) {
String dig = "";
//匹配跳首页
if (back) {
dig = "已经跳到首页";
} else {
//不匹配
dig = "跳到登陆页";
}
return dig;
}
}
普通用户
package com.atmae.templateMethod;
import java.util.ArrayList;
import java.util.List;
import java.util.Scanner;
/**
* @Author: Mae
* @Date: 2022/4/14
* @Time: 8:11
* @Description:
*/
public class UserLogin extends Login {
@Override
public List<String> forwardPage() {
//输入用户名和密码
String username = null, password = null;
Scanner scanner = new Scanner(System.in);
scanner.next(username);
scanner.next(password);
List<String> list = new ArrayList<>();
list.add(username);
list.add(password);
return list;
}
@Override
public boolean back(List<String> list) {
//从后台数据库获取密码
//模拟:
String passwordByDatabase = "123456";
return list.get(1).equals(passwordByDatabase);
}
@Override
public String action(boolean back) {
String dig="";
//匹配跳首页
if (back) {
dig="已经跳到首页";
}else{
//不匹配
dig="跳到登陆页";
}
return dig;
}
}
3、客户端
package com.atmae.templateMethod;
/**
* @Author: Mae
* @Date: 2022/4/14
* @Time: 9:01
* @Description:
*/
public class Client {
public static void main(String[] args) {
//管理员登录
Login admin=new AdminLogin();
admin.templateMethod();
}
}
五、UML图
六、模板方法模式使用场景
- 只希望客户端扩展某个特定算法步骤, 而不是整个算法或其结构时, 可使用模板方法模式。
- 当多个类的算法除一些细微不同之外几乎完全一样时, 你可使用该模式。 但其后果就是, 只要算法发生变化, 你就可能需要修改所有的类。
七、总结
优点
- 允许客户端重写一个大型算法中的特定部分, 使得算法其他部分修改对其所造成的影响减小。
- 可将重复代码提取到一个超类中
缺点
- 模板方法中的步骤越多, 其维护工作就可能会越困难。
- 违反里氏替换原则,(父类拥有的性质 子类不一定成立了)
八、与其他模式的关系
- 工厂方法模式是模板方法模式的一种特殊形式。 同时, 工厂方法可以作为一个大型模板方法中的一个步骤。
- 模板方法基于继承机制: 它允许你通过扩展子类中的部分内容来改变部分算法。
策略模式基于组合机制: 你可以通过对相应行为提供不同的策略来改变对象的部分行为。
模板方法在类层次上运作, 因此它是静态的。
策略在对象层次上运作, 因此允许在运行时切换行为。