java设计模式学习之【模板方法模式】

文章目录

引言

设想你正在准备一顿晚餐,无论你想做意大利面、披萨还是沙拉,制作过程中都有一些共同的步骤:准备原料、加工食物、摆盘。这里,整个烹饪流程就像一个模板,而具体的菜肴则在这个模板的基础上添加了特有的步骤。在软件开发中,我们经常遇到类似的情况,某些过程的结构相同,但某些步骤的具体实现不同。模板方法模式正是用于解决这类问题的一种设计模式,它在定义算法骨架的同时,将一些步骤的实现延迟到子类。

模板方法模式简介

定义与用途

模板方法模式(Template Method Pattern)是一种行为型设计模式,它在父类中定义了一个操作的算法骨架,而将一些步骤的具体实现延迟到子类中。通过这种方式,可以重新定义算法的某些步骤而不改变算法的结构。

实现方式

实现模板方法模式通常涉及以下几个关键组件:

  • 抽象类(Abstract Class):定义了模板方法和算法的骨架。模板方法设置为 final,这样它就不能被重写。它调用一系列的操作,其中一些操作由子类实现。
  • 具体类(Concrete Class):实现抽象类中的抽象方法,定义了算法中与特定主题相关的步骤。

使用场景

模板方法模式适用于以下场景:

  • 当有多个算法具有相同的算法结构,但算法的某些步骤在不同的情况下有不同的实现时。
  • 当需要控制子类扩展的点时,可以在一些操作中定义钩子(hook)。

例如:

  • 数据解析框架: 定义一个解析数据的模板方法,具体的解析步骤如读取数据、分析数据和处理数据可以在子类中实现。
  • 软件构建过程: 软件构建工具可以定义一系列构建步骤的模板,如清理、编译、测试和打包,具体的步骤根据不同的项目而定制。
  • 游戏设计: 游戏可以定义一个游戏流程模板,如开始游戏、进行游戏和结束游戏,具体的游戏逻辑在不同的游戏子类中实现。

优势与劣势

  • 优势
    • 提供了代码复用的平台,通过模板方法,公共代码移动到单一位置,减少代码冗余。
    • 提供了一种扩展部分算法的方法,子类可以在不改变算法结构的情况下重新定义算法的某些特定步骤。
  • 劣势
    • 对于每个不同的实现,都需要一个新的子类,可能会导致系统中类的数量增加。
    • 有时候可能违背了里氏替换原则,因为子类改变了父类的预期行为。

在Spring框架中的应用

1. JdbcTemplate
JdbcTemplate 是Spring提供的一个优秀的数据库操作工具,它实现了模板方法模式。Spring定义了一个抽象的 JdbcOperations 接口,提供了执行数据库操作的模板方法。JdbcTemplate 类实现了这些方法,管理数据库连接、声明语句的创建和执行、结果集的遍历处理等。用户只需要提供SQL语句和定义如何映射结果集到对象,其他的数据库操作细节(如异常处理、事务管理等)都由模板方法处理。

2. TransactionTemplate
Spring的 TransactionTemplate 也是模板方法模式的一个应用实例。它提供了一个模板,用于执行带有事务管理的代码块。用户只需要提供需要在事务环境中执行的代码,而事务的管理(开始、提交、回滚等)则是在模板内部处理的。这使得用户不需要直接与底层的事务API打交道,简化了事务管理的代码。

3. Spring Web MVC
在Spring Web MVC框架中,DispatcherServlet 提供了一个模板方法来处理HTTP请求。它定义了处理请求的整体流程:解析请求、寻找对应的处理器、渲染视图等。在这个流程中,可以插入各种预处理器、后处理器和视图解析器来定制请求处理的行为。开发者通过扩展特定的方法,提供自己的处理逻辑。

4. Spring Security
Spring Security中的过滤器链也是一个模板方法模式的实例。它定义了一系列的安全检查过程,每一个过滤器都是一个检查的实现。开发者可以通过添加或移除过滤器,或者自定义过滤器来定制安全检查的流程。

游戏设计示例


步骤 1:创建一个带有模板方法的抽象类

java 复制代码
public abstract class Game {
   abstract void initialize();
   abstract void startPlay();
   abstract void endPlay();

   // 模板方法
   public final void play(){

      // 初始化游戏
      initialize();

      // 开始游戏
      startPlay();

      // 结束游戏
      endPlay();
   }
}

Game 是一个抽象类,定义了三个抽象方法:initialize、startPlay 和 endPlay,用于子类实现具体的游戏初始化、开始和结束的行为。它还定义了一个模板方法 play,该方法按顺序调用这三个方法,设置为 final 以防止子类覆盖。

步骤 2:创建扩展上述类的具体类

java 复制代码
public class Cricket extends Game {

   @Override
   void endPlay() {
      System.out.println("板球游戏结束了!");
   }

   @Override
   void initialize() {
      System.out.println("板球游戏初始化了!开始玩吧。");
   }

   @Override
   void startPlay() {
      System.out.println("板球游戏开始了。享受游戏!");
   }
}

Cricket 是 Game 的一个具体子类,它实现了板球游戏的具体行为。

java 复制代码
public class Football extends Game {

   @Override
   void endPlay() {
      System.out.println("足球游戏结束了!");
   }

   @Override
   void initialize() {
      System.out.println("足球游戏初始化了!开始玩吧。");
   }

   @Override
   void startPlay() {
      System.out.println("足球游戏开始了。享受游戏!");
   }
}

Football 是另一个具体的 Game 子类,实现了足球游戏的具体行为。

步骤 3:使用游戏的模板方法 play() 来演示游戏的定义方式

java 复制代码
public class TemplatePatternDemo {
   public static void main(String[] args) {

      Game game = new Cricket();
      game.play();
      System.out.println();
      game = new Football();
      game.play();      
   }
}

在这个演示类中,先创建了一个 Cricket 对象,并调用其 play 方法来执行整个板球游戏流程。然后,创建了一个 Football 对象,并再次调用 play 方法来执行足球游戏流程。

这个示例演示了模板方法模式如何定义算法的骨架,同时将一些步骤的具体实现延迟到子类中。通过这种方式,Cricket 和 Football 可以有自己独特的游戏流程,同时共享游戏流程的结构。这使得算法的结构定义一次,可以被多次复用,而且更容易进行扩展。

代码地址

23种设计模式相关代码后续会逐步提交到github上,方便学习,欢迎指点:
代码地址

https://github.com/RuofeiSun/lf-23Pattern

相关推荐
吾日三省吾码1 小时前
JVM 性能调优
java
弗拉唐2 小时前
springBoot,mp,ssm整合案例
java·spring boot·mybatis
oi772 小时前
使用itextpdf进行pdf模版填充中文文本时部分字不显示问题
java·服务器
少说多做3433 小时前
Android 不同情况下使用 runOnUiThread
android·java
知兀3 小时前
Java的方法、基本和引用数据类型
java·笔记·黑马程序员
蓝黑20203 小时前
IntelliJ IDEA常用快捷键
java·ide·intellij-idea
Ysjt | 深3 小时前
C++多线程编程入门教程(优质版)
java·开发语言·jvm·c++
shuangrenlong3 小时前
slice介绍slice查看器
java·ubuntu
牧竹子3 小时前
对原jar包解压后修改原class文件后重新打包为jar
java·jar