Java - GoF设计模式详解14(模版方法模式)
作者:hangge | 2023-06-02 09:04
十四、模版方法模式
1,基本介绍
(1)模板方法模式(Template Method)中,抽象类定义了一个算法的骨架,而将一些步骤延迟到子类中。模板方法模式使得子类可以不改变一个算法的结构即可重定义该算法的某些特定步骤。
钩子方法:指在模版方法中的某些步骤中留下的一个空位,允许子类在不改变算法结构的情况下,增加新的行为。钩子方法通常是一些空方法,由子类选择性地覆盖。
(2)该模式中包含的角色及其职责如下:
- 抽象类(Abstract Class):定义了算法的骨架,其中一些步骤被延迟到子类中实现。
- 具体类(Concrete Class):实现抽象类中声明的抽象方法,并提供它们的具体实现。
2,使用样例
(1)下面我们使用模版方法模式来实现各种食物的制作。虽然各种食物的食材、加工方式各不相同,但总体的算法骨架都是一样的(包含准备原材料、加热食物、装盘)。因此首先我们定义了如下的抽象类,抽象类定义了算法的骨架,而将具体的步骤延迟到子类中实现。
// 食物抽象类 abstract class Food { // 准备原材料 abstract void prepareIngredients(); // 加热食物 abstract void cook(); // 装盘 abstract void serve(); // 准备、烹饪和装盘是一个完整的流程,因此我们可以将它们组合在一起 public final void makeFood() { prepareIngredients(); cook(); serve(); } }
(2)然后,我们可以创建一些子类来表示具体的食物类型。这些子类可以重写抽象类中的抽象方法,并提供它们的具体实现。
- 下面是汉堡类的代码:
// 汉堡类 class Hamburger extends Food { @Override void prepareIngredients() { System.out.println("准备汉堡所需的原材料:牛肉、面包、蔬菜等"); } @Override void cook() { System.out.println("使用烤箱加热汉堡"); } @Override void serve() { System.out.println("将汉堡装盘,准备交付客户"); } }
- 下面是意大利面类的代码:
// 意大利面 class Spaghetti extends Food { @Override void prepareIngredients() { System.out.println("准备意大利面所需的原材料:面条、番茄酱、肉丸等"); } @Override void cook() { // 将意大利面加热,直到它烹饪好为止 System.out.println("使用捞面锅加热意大利"); } @Override void serve() { System.out.println("将意大利面装盘,准备交付客户"); } }
(3)最后测试一下,我们可以使用这些类来准备食物。
public class Test { public static void main(String[] args) { // 制作汉堡 Food hamburger = new Hamburger(); hamburger.makeFood(); // 制作意大利面 Food spaghetti = new Spaghetti(); spaghetti.makeFood(); } }
附一:JDK 中的模版方法模式
(1)java.util.AbstractList、java.util.AbstractSet、java.util.AbstractMap 等抽象类,它们都有一个模板方法 size(),它定义了计算集合大小的通用算法。
- java.util.AbstractList 的子类有 java.util.ArrayList、java.util.Vector 等。
- java.util.AbstractSet 的子类有 java.util.HashSet、java.util.LinkedHashSet 等。
- java.util.AbstractMap 的子类有 java.util.HashMap、java.util.TreeMap、java.util.LinkedHashMap 等。
(2)java.io.InputStream、java.io.OutputStream、java.io.Reader、java.io.Writer 等抽象类,它们都有一个模板方法 close(),它定义了关闭流的通用算法。
- java.io.InputStream 的子类有 java.io.FileInputStream、java.io.ByteArrayInputStream 等。
- java.io.OutputStream 的子类有 java.io.FileOutputStream、java.io.ByteArrayOutputStream 等。
- java.io.Reader 的子类有 java.io.FileReader、java.io.StringReader 等。
- java.io.Writer 的子类有 java.io.FileWriter、java.io.StringWriter 等。
(3)java.util.Comparator 接口,它有一个模板方法 compare(),它定义了比较两个对象的通用算法。
- 我们可以自己实现 java.util.Comparator 接口,以便提供自定义的比较算法。例如,可以实现一个 Comparator 来按照字符串的长度来比较字符串,或者按照对象的某个属性来比较对象。
(4)java.util.concurrent.Callable 接口,它有一个模板方法 call(),它定义了执行任务的通用算法。
- 我们可以自己实现 java.util.concurrent.Callable 接口,以便提供自定义的任务执行算法。例如,可以实现一个 Callable 来执行一个耗时的计算任务,或者执行一个网络请求任务等。
附二:Spring 中的模版方法模式
(1)JdbcTemplate:这是 Spring JDBC 模块中的一个常用类,它封装了 JDBC 的基本操作,允许开发人员在不编写大量样板代码的情况下执行数据库操作。JdbcTemplate 使用了模板模式,它提供了一组抽象方法,用于定义数据库操作的流程,然后允许子类实现这些方法,提供具体的实现逻辑。
- 例如,我们可以使用 JdbcTemplate 来执行 SQL 语句,并且可以重写它的 query() 方法来自定义结果集的处理逻辑。
(2)RestTemplate:这是 Spring Web 模块中的一个常用类,它提供了一组抽象方法,用于定义 HTTP 请求的流程,然后允许子类实现这些方法,提供具体的实现逻辑。
(3)JpaRepository:这是 Spring Data JPA 模块中的一个常用接口,它提供了一组抽象方法,用于定义 JPA 数据访问的流程,然后允许子类实现这些方法,提供具体的实现逻辑。
(4)MongoTemplate:这是 Spring Data MongoDB 模块中的一个常用类,它提供了一组抽象方法,用于定义 MongoDB 数据访问的流程,然后允许子类实现这些方法,提供具体的实现逻辑。
(5)HibernateJpaVendorAdapter:这是 Spring Data JPA 模块中的一个常用类,它封装了 Hibernate 的 JPA 实现,提供了一组抽象方法,用于定义 Hibernate 的初始化流程,然后允许子类实现这些方法,提供具体的实现逻辑。
(6)AbstractRoutingDataSource:这是 Spring JDBC 模块中的一个常用类,它提供了一组抽象方法,用于定义数据源路由的流程,然后允许子类实现这些方法,提供具体的实现逻辑。
(7)AbstractJmsListeningContainer:这是 Spring JMS 模块中的一个常用类,它提供了一组抽象方法,用于定义 JMS 监听器容器的流程,然后允许子类实现这些方法,提供具体的实现逻辑。
全部评论(0)