什么是模板方法?
模板方法模式允许你在抽象类中定义算法的框架(一套通用的执行流程),而让子类实现具体的细节,从而达到代码复用和功能扩展的目的。
简单来说,大体流程都一样,只是在某些步骤不一样。(也就是可以在某些方法中修改执行的逻辑)
模板方法的应用场景
- 多个支付方式(如信用卡支付、支付宝支付)可能有相似的支付流程,但具体的支付逻辑会有所不同
- Spring 框架中的 JdbcTemplate 和 HibernateTemplate,它们定义了数据库操作的模板,用户只需提供具体的 SQL 语句或查询逻辑
从实际场景中聊模板方法
举一个例子:
不知道你们是否用过在线执行代码的平台,就是那种不用装开发环境,就可以执行简单的代码的平台
菜鸟教程:在线编辑器,在线运行代码,在线编译器大全 - 在线工具(cainiaojc.com)
如果说我们要做一个这样子的平台,从前端上传代码,到执行代码,最后输出结果,流程是怎么样子的?
其实主要有这些步骤,以 Java 代码为例:
1)前端上传代码,将用户代码保存为文件(Main.java)
2)编译代码,得到 class 文件
3)执行代码,得到输出结果
4)收集输出结果
5)文件清理,释放空间
流程大致就是这样子的,但是有没有想过一个问题,就是这个代码是跑在哪里的?你自己的宿主机上?
先来说说,代码跑在自己的宿主机上有什么问题?
- 比如有人写一个 sleep(一万年),直接可以让程序卡死。
- 不断的占用内存空间,直到堆溢出
- 一些骚操作,把你l数据库的密码给读出来
- ..............
那么怎么解决?
将代码的运行环境,和宿主机隔离开,创建一个全新的环境,提供的用户使用。那么我们使用 Docker 就可以隔离宿主机了。
那么 Docker 中执行代码的流程又是怎么样子的?
1)前端上传代码,将用户代码保存为文件(Main.java)
2)编译代码,得到 class 文件
3)将编译好的 class 文件,上传到容器中,Docker 中执行代码
4)收集输出结果
5)文件清理,清除容器,释放空间
看到这里你是不是发现了,哦!除了第三步和第五步,大致的流程都一样。我们自己写一个抽象的方法,让其子类去继承对应的方法,针对自己子类的实现细节的不同,去重写父类的中的方法。共同的逻辑,直接复用父类的方法即可。这样子,大大的复用了代码。
模板方法的具体实现
这里来提供 Java 的伪代码,不做具体的实现。
定义一个抽象的方法,实现具体的流程:
public abstract class AbstractTemplate {
public void execute() {
// 1. 把用户的代码保存为文件
saveCodeToFile();
// 2. 编译代码
compileFile();
// 3. 执行代码
executeCode();
// 4. 收集整理输出结果
getOutput();
// 5. 文件清理
deleteFile();
}
public void saveCodeToFile() {
System.out.println("保存代码");
}
public void compileFile() {
System.out.println("编译代码");
}
public void executeCode () {
System.out.println("默认执行代码");
}
public void getOutput() {
System.out.println("获取输出结果");
}
public void deleteFile() {
System.out.println("文件清理");
}
}
Java 原生代码实现(在宿主机中执行代码)
public class JavaNaiveSandBox extends AbstractTemplate{
// 直接调用父类的方法
@Override
public void execute() {
super.execute();
}
}
使用Docker来执行代码,并重写 执行代码 和文件清理 的逻辑
public class DockerSandBox extends AbstractTemplate{
/**
* 重写父类的方法,定义自己的逻辑
*/
@Override
public void executeCode() {
System.out.println("使用 docker 执行代码");
}
@Override
public void deleteFile() {
// 清理后文件后
super.deleteFile();
// 顺便在清理容器
System.out.println("顺便在清理容器");
}
}
测试输出:
public static void main(String[] args) {
JavaNaiveSandBox javaNaiveSandBox = new JavaNaiveSandBox();
javaNaiveSandBox.execute();
System.out.println("------------");
DockerSandBox dockerSandBox = new DockerSandBox();
dockerSandBox.execute();
}
输出结果: