编程设计模式之模板方法模式

编程设计模式之模板方法模式

为什么有模板方法模式?

在软件开发中,有时候我们会遇到一些算法框架,其中一些步骤是固定的,而另一些步骤则可能因应用场景不同而变化。如果每次都直接在代码中硬编码这些固定的步骤,会导致代码的重复和扩展困难。模板方法模式就是为了解决这一问题而诞生的。

模板方法模式的设计思路

模板方法模式定义了一个算法的骨架,将具体步骤的实现延迟到子类中。它包含两种类型的方法:

  1. 模板方法(Template Method):定义了算法的骨架,其中包含了算法的主要逻辑,调用了一系列的抽象方法,这些抽象方法需要在具体子类中实现。
  2. 钩子方法(Hook Method):在模板方法中被声明并提供默认实现,子类可以选择性地覆盖它们来扩展或修改算法的行为。

模板方法模式包含三个主要角色:

  1. AbstractClass(抽象类):定义了一个模板方法,其中包含算法的骨架和一些抽象方法,这些抽象方法由具体子类来实现。
  2. ConcreteClass(具体子类):实现了抽象类中的抽象方法,完成算法的具体步骤。
  3. Hook Method(钩子方法):在抽象类中提供了默认的实现,子类可以选择性地覆盖它们。

Java示例代码

下面是一个简单的Java示例代码,演示了模板方法模式的应用:

java 复制代码
// 抽象类
abstract class AbstractClass {
    // 模板方法
    public final void templateMethod() {
        primitiveOperation1();
        primitiveOperation2();
        hookMethod();
    }

    // 基本方法1(抽象方法)
    abstract void primitiveOperation1();

    // 基本方法2(抽象方法)
    abstract void primitiveOperation2();

    // 钩子方法(默认实现)
    void hookMethod() {
        System.out.println("钩子方法默认实现");
    }
}

// 具体子类A
class ConcreteClassA extends AbstractClass {
    @Override
    void primitiveOperation1() {
        System.out.println("具体子类A中的基本方法1的实现");
    }

    @Override
    void primitiveOperation2() {
        System.out.println("具体子类A中的基本方法2的实现");
    }

    @Override
    void hookMethod() {
        System.out.println("具体子类A中的钩子方法的实现");
    }
}

// 具体子类B
class ConcreteClassB extends AbstractClass {
    @Override
    void primitiveOperation1() {
        System.out.println("具体子类B中的基本方法1的实现");
    }

    @Override
    void primitiveOperation2() {
        System.out.println("具体子类B中的基本方法2的实现");
    }
}

// 客户端代码
public class Main {
    public static void main(String[] args) {
        AbstractClass concreteClassA = new ConcreteClassA();
        concreteClassA.templateMethod();

        AbstractClass concreteClassB = new ConcreteClassB();
        concreteClassB.templateMethod();
    }
}

SpringBoot工程中如何应用模板方法模式

在SpringBoot工程中,模板方法模式常被用于定义一些基础的流程或骨架,并在具体子类中实现特定的业务逻辑。例如,Spring框架中的JdbcTemplate就是一个典型的模板方法模式的应用。

下面是一个简单的示例,演示了如何在SpringBoot工程中应用模板方法模式:

java 复制代码
import org.springframework.jdbc.core.JdbcTemplate;

// 抽象模板类
abstract class JdbcOperationTemplate {
    protected final JdbcTemplate jdbcTemplate;

    public JdbcOperationTemplate(JdbcTemplate jdbcTemplate) {
        this.jdbcTemplate = jdbcTemplate;
    }

    // 模板方法
    public final void execute() {
        openConnection();
        doOperation();
        closeConnection();
    }

    // 抽象方法:打开连接
    protected abstract void openConnection();

    // 抽象方法:执行操作
    protected abstract void doOperation();

    // 抽象方法:关闭连接
    protected abstract void closeConnection();
}

// 具体子类:查询操作
class QueryOperation extends JdbcOperationTemplate {
    public QueryOperation(JdbcTemplate jdbcTemplate) {
        super(jdbcTemplate);
    }

    @Override
    protected void openConnection() {
        System.out.println("打开数据库连接");
    }

    @Override
    protected void doOperation() {
        jdbcTemplate.query("SELECT * FROM table", (rs, rowNum) -> {
            // 处理结果集
            return null;
        });
    }

    @Override
    protected void closeConnection() {
        System.out.println("关闭数据库连接");
    }
}

// 客户端代码
public class Main {
    public static void main(String[] args) {
        JdbcTemplate jdbcTemplate = new JdbcTemplate(); // 实际项目中应该从Spring容器中注入
        JdbcOperationTemplate operation = new QueryOperation(jdbcTemplate);
        operation.execute();
    }
}

通过这种方式,在SpringBoot工程中,我们可以定义一些通用的数据库操作流程,并通过具体的子类来实现特定的业务逻辑,实现代码的复用和灵活性。

相关推荐
ldj202034 分钟前
SpringBoot为什么使用new RuntimeException() 来获取调用栈?
java·spring boot·后端
超龄超能程序猿34 分钟前
Spring 应用中 Swagger 2.0 迁移 OpenAPI 3.0 详解:配置、注解与实践
java·spring boot·后端·spring·spring cloud
江南一点雨42 分钟前
Tokenizer 和 BPE
后端
风象南1 小时前
SpringBoot配置属性热更新的轻量级实现
java·spring boot·后端
洛阳泰山1 小时前
Spring Boot 整合 Nacos 实战教程:服务注册发现与配置中心详解
java·spring boot·后端·nacos
江南一点雨1 小时前
ChatGPT与最大似然估计
后端
程序员爱钓鱼2 小时前
Go语言实战案例-判断一个数是否为质数
后端·google·go
程序员爱钓鱼2 小时前
Go语言实战案例-读取本地文本文件内容
后端·google·go
mCell10 小时前
Go 并发编程基础:从 Goroutine 到 Worker Pool 实践
后端·性能优化·go
Python智慧行囊11 小时前
Flask 框架(一):核心特性与基础配置
后端·python·flask