深入解析Java中的模板方法模式:抽象与实现的优雅结合
个人名片
🎓作者简介:java领域优质创作者
🌐个人主页:码农阿豪
📞工作室:新空间代码工作室(提供各种软件服务)
💌个人邮箱:[2435024119@qq.com]
📱个人微信:15279484656
🌐个人导航网站:www.forff.top
💡座右铭:总有人要赢。为什么不能是我呢?
- 专栏导航:
码农阿豪系列专栏导航
面试专栏:收集了java相关高频面试题,面试实战总结🍻🎉🖥️
Spring5系列专栏:整理了Spring5重要知识点与实战演练,有案例可直接使用🚀🔧💻
Redis专栏:Redis从零到一学习分享,经验总结,案例实战💐📝💡
全栈系列专栏:海纳百川有容乃大,可能你想要的东西里面都有🤸🌱🚀
目录
深入解析Java中的模板方法模式:抽象与实现的优雅结合
一、模板方法模式概述
模板方法模式(Template Method Pattern)是行为型设计模式中的一种,它定义了一个操作中的算法骨架,而将一些步骤延迟到子类中实现。模板方法使得子类可以不改变算法结构的情况下,重新定义算法中的某些特定步骤。
1.1 模式定义
模板方法模式的核心思想是:在一个抽象类中定义一个操作中的算法骨架(即"模板方法"),将某些步骤的具体实现延迟到子类中。这样可以在不改变算法结构的情况下,让子类重新定义某些特定的步骤。
1.2 模式结构
模板方法模式主要包含两个角色:
- 抽象类(Abstract Class):定义算法骨架,包含模板方法和基本方法
- 具体子类(Concrete Class):实现抽象类中的抽象方法,完成特定步骤的具体实现
1.3 模式优点
- 封装不变部分,扩展可变部分
- 提取公共代码,便于维护
- 行为由父类控制,子类实现细节
- 符合"开闭原则",增加新的子类实现新的功能
二、模板方法模式的实现
2.1 基本实现结构
让我们先看一个模板方法模式的基本实现代码:
// 抽象类定义模板方法和基本方法
public abstract class AbstractClass {
// 模板方法,定义算法骨架(通常声明为final,防止子类重写)
public final void templateMethod() {
primitiveOperation1();
primitiveOperation2();
concreteOperation();
hook();
}
// 基本方法1:抽象方法,由子类实现
protected abstract void primitiveOperation1();
// 基本方法2:抽象方法,由子类实现
protected abstract void primitiveOperation2();
// 基本方法3:具体方法,已实现
protected void concreteOperation() {
// 实现代码
System.out.println("AbstractClass: 执行concreteOperation方法");
}
// 钩子方法:默认空实现,子类可选择性覆盖
protected void hook() {}
}
2.2 具体子类实现
// 具体子类A
public class ConcreteClassA extends AbstractClass {
@Override
protected void primitiveOperation1() {
System.out.println("ConcreteClassA: 实现primitiveOperation1方法");
}
@Override
protected void primitiveOperation2() {
System.out.println("ConcreteClassA: 实现primitiveOperation2方法");
}
@Override
protected void hook() {
System.out.println("ConcreteClassA: 覆盖hook方法");
}
}
// 具体子类B
public class ConcreteClassB extends AbstractClass {
@Override
protected void primitiveOperation1() {
System.out.println("ConcreteClassB: 实现primitiveOperation1方法");
}
@Override
protected void primitiveOperation2() {
System.out.println("ConcreteClassB: 实现primitiveOperation2方法");
}
// 不覆盖hook方法,使用默认实现
}
2.3 客户端调用
public class Client {
public static void main(String[] args) {
AbstractClass classA = new ConcreteClassA();
classA.templateMethod();
System.out.println("-------------------");
AbstractClass classB = new ConcreteClassB();
classB.templateMethod();
}
}
输出结果:
ConcreteClassA: 实现primitiveOperation1方法
ConcreteClassA: 实现primitiveOperation2方法
AbstractClass: 执行concreteOperation方法
ConcreteClassA: 覆盖hook方法
-------------------
ConcreteClassB: 实现primitiveOperation1方法
ConcreteClassB: 实现primitiveOperation2方法
AbstractClass: 执行concreteOperation方法
三、模板方法模式的核心要素
3.1 模板方法
模板方法是定义在抽象类中的,它给出了一个顶级逻辑的骨架,而逻辑的组成步骤在抽象类中实现或推迟到子类实现。模板方法通常会定义为final,以防止子类重写改变算法结构。
3.2 基本方法
基本方法是模板方法的组成部分,分为三种类型:
- 抽象方法:由抽象类声明,由具体子类实现
- 具体方法:由抽象类声明并实现,子类可以继承或重写
- 钩子方法:由抽象类声明并实现(通常为空实现),子类可选择性地覆盖
3.3 钩子方法
钩子方法是一种特殊的基本方法,它提供了默认实现(通常是空实现),子类可以根据需要决定是否覆盖它。钩子方法使得子类能够对模板方法中某些步骤进行干预,而不必改变模板方法的结构。
四、模板方法模式的应用场景
模板方法模式在以下场景中特别有用:
- 算法骨架固定,但部分步骤可变:当多个类有相同的方法,且逻辑基本相同,只是某些具体步骤不同时。
- 代码复用:当需要抽取公共行为到父类中,避免代码重复时。
- 控制子类扩展:当需要控制子类扩展方式,只允许子类实现特定方法时。
4.1 Java中的典型应用
模板方法模式在Java中有许多经典应用:
- Servlet API:
HttpServlet类中的service()方法就是一个模板方法,它调用了doGet()、doPost()等方法。 - Java集合框架:
AbstractList、AbstractSet等抽象类使用了模板方法模式。 - JUnit:测试框架中的
TestCase类使用了模板方法模式。
五、实战案例:数据库操作模板
让我们通过一个更实际的例子来理解模板方法模式:数据库操作模板。
5.1 定义数据库操作模板
public abstract class DatabaseTemplate {
// 模板方法,定义数据库操作流程
public final void execute() {
connect();
open();
operate();
if (shouldCommit()) {
commit();
}
close();
}
// 基本方法:连接数据库
private void connect() {
System.out.println("建立数据库连接...");
}
// 基本方法:打开会话
private void open() {
System.out.println("打开数据库会话...");
}
// 抽象方法:具体操作,由子类实现
protected abstract void operate();
// 基本方法:提交事务
private void commit() {
System.out.println("提交事务...");
}
// 钩子方法:决定是否提交事务
protected boolean shouldCommit() {
return true;
}
// 基本方法:关闭连接
private void close() {
System.out.println("关闭数据库连接...");
}
}
5.2 具体实现类
// 查询操作
public class QueryOperation extends DatabaseTemplate {
@Override
protected void operate() {
System.out.println("执行数据库查询操作...");
}
@Override
protected boolean shouldCommit() {
return false; // 查询不需要提交
}
}
// 更新操作
public class UpdateOperation extends DatabaseTemplate {
@Override
protected void operate() {
System.out.println("执行数据库更新操作...");
}
}
5.3 客户端使用
public class DatabaseClient {
public static void main(String[] args) {
DatabaseTemplate query = new QueryOperation();
query.execute();
System.out.println("------------------");
DatabaseTemplate update = new UpdateOperation();
update.execute();
}
}
输出结果:
建立数据库连接...
打开数据库会话...
执行数据库查询操作...
关闭数据库连接...
------------------
建立数据库连接...
打开数据库会话...
执行数据库更新操作...
提交事务...
关闭数据库连接...
六、模板方法模式的变体与扩展
6.1 带参数的模板方法
模板方法可以接收参数,这些参数可以在算法骨架中使用:
public abstract class AbstractClass {
public final void templateMethod(Object param) {
// 使用param参数
primitiveOperation1(param);
if (validate(param)) {
primitiveOperation2();
}
hook();
}
// ...其他方法
}
6.2 回调函数的替代实现
在Java 8+中,可以使用函数式接口和Lambda表达式来实现类似模板方法模式的效果:
public class TemplateMethodWithLambda {
public void execute(Runnable operation1, Runnable operation2) {
System.out.println("前置操作");
operation1.run();
System.out.println("中间操作");
operation2.run();
System.out.println("后置操作");
}
}
// 使用
new TemplateMethodWithLambda().execute(
() -> System.out.println("自定义操作1"),
() -> System.out.println("自定义操作2")
);
七、模板方法模式与策略模式的比较
模板方法模式和策略模式都用于封装算法,但它们有以下区别:
-
实现方式:
- 模板方法:基于继承,通过子类实现部分步骤
- 策略模式:基于组合,通过注入不同策略对象实现不同行为
-
控制权:
- 模板方法:父类控制算法流程
- 策略模式:客户端控制使用哪种策略
-
灵活性:
- 模板方法:算法结构固定,只能改变部分步骤
- 策略模式:可以完全替换算法
选择依据:
- 如果需要固定算法结构,只允许改变部分步骤,使用模板方法
- 如果需要完全替换算法,使用策略模式
八、模板方法模式的最佳实践
- 模板方法应声明为final:防止子类重写改变算法结构
- 尽量减少抽象方法的数量:过多的抽象方法会增加子类实现的负担
- 合理使用钩子方法:为子类提供必要的扩展点,但不要过度使用
- 命名约定:可以遵循命名约定,如模板方法命名为"doXxx",钩子方法命名为"onXxx"
- 文档说明:清楚地文档化模板方法和各个基本方法的职责
九、总结
模板方法模式是一种简单但强大的行为型设计模式,它通过定义算法骨架并将具体步骤延迟到子类实现,实现了代码复用和扩展性的平衡。该模式特别适用于具有固定流程但部分步骤需要灵活变化的场景。
在实际开发中,模板方法模式广泛应用于框架设计、算法封装等领域。理解并合理运用这一模式,可以帮助我们写出更加清晰、可维护的面向对象代码。
通过本文的详细讲解和代码示例,相信读者已经对Java中的模板方法模式有了深入的理解。在适当的场景下应用这一模式,可以显著提高代码的质量和可维护性。


浙公网安备 33010602011771号