Java设计模式之模板方法模式Template Method Pattern详解

yizhihongxing

Java设计模式之模板方法模式Template Method Pattern详解

概述

模板方法模式是一种行为设计模式。在该模式中,有一个抽象类作为模板,其中定义了算法的骨架,具体实现延迟到子类中。这种模式属于行为型模式。

在模板方法模式中,父类定义一个模板方法,该方法作为算法的骨架,而实际的子类实现会覆盖其中的某些步骤,但是整个算法的骨架不会改变。

实现

模板方法模式包含以下角色:

  • 抽象类(Abstract Class):定义一个模板方法和一些抽象方法。
  • 具体类(Concrete Class):实现抽象类中的抽象方法,并覆盖父类中的模板方法中已有的部分逻辑。

抽象类

在抽象类中,定义一个模板方法,该方法中会调用一系列抽象方法。例如:

public abstract class AbstractClass {

   final void templateMethod(){
      firstAbstractOperation();
      secondAbstractOperation();
      thirdAbstractOperation();
   }

   abstract void firstAbstractOperation();
   abstract void secondAbstractOperation();
   abstract void thirdAbstractOperation();    
}

在这个例子中,我们定义了一个抽象类 AbstractClass,其中 templateMethod() 方法是具体算法的骨架。在这个方法中,我们调用了三个抽象方法:firstAbstractOperation()secondAbstractOperation()thirdAbstractOperation()

具体类

在具体类中,我们要实现抽象类中的所有抽象方法,并覆盖父类中的模板方法的已有部分逻辑。例如:

public class ConcreteClass extends AbstractClass {

   void firstAbstractOperation() {
      System.out.println("ConcreteClass firstAbstractOperation");
   }

   void secondAbstractOperation() {
      System.out.println("ConcreteClass secondAbstractOperation");
   }

   void thirdAbstractOperation() {
      System.out.println("ConcreteClass thirdAbstractOperation");       
   }
}

在这个例子中,我们定义了一个具体类 ConcreteClass,并实现了抽象类中的三个抽象方法。这些方法将分别被 templateMethod() 调用。

例子

下面通过两个例子来说明模板方法模式的应用。

例子1:煮咖啡和茶

我们假设有一个咖啡制作过程,又有一个茶制作过程,这两个过程有一些共同的步骤。例如,都需要将水煮沸、将水倒入杯子中等等。

我们可以使用模板方法模式来实现这个例子。首先,我们定义一个抽象类 Beverage,其中 prepareRecipe() 方法是模板方法:

public abstract class Beverage {

    // 模板方法
    public final void prepareRecipe() {
        boilWater();
        brew();
        pourInCup();
        addCondiments();
    }

    void boilWater() {
        System.out.println("Boiling water");
    }

    void pourInCup() {
        System.out.println("Pouring into cup");
    }

    abstract void brew();

    abstract void addCondiments();
}

Beverage 类中,我们定义了一个模板方法 prepareRecipe(),在这个方法中,我们定义了几个步骤:boilWater()brew()pourInCup()addCondiments()

接下来,我们定义两个具体类 CoffeeTea,这两个类分别对应咖啡制作和茶制作两个过程:

public class Coffee extends Beverage {

    void brew() {
        System.out.println("Dripping Coffee through filter");
    }

    void addCondiments() {
        System.out.println("Adding Sugar and Milk");
    }
}

public class Tea extends Beverage {

    void brew() {
        System.out.println("Steeping the tea");
    }

    void addCondiments() {
        System.out.println("Adding Lemon");
    }
}

CoffeeTea 类中,我们分别实现了 brew()addCondiments() 两个抽象方法,这些方法将在 prepareRecipe() 中被调用。

现在,我们可以使用这些类来制作咖啡和茶:

Beverage coffee = new Coffee();
coffee.prepareRecipe();

Beverage tea = new Tea();
tea.prepareRecipe();

输出结果如下:

Boiling water
Dripping Coffee through filter
Pouring into cup
Adding Sugar and Milk

Boiling water
Steeping the tea
Pouring into cup
Adding Lemon

从输出结果可以看出,咖啡和茶的制作过程中,都共用了 Beverage 类中定义的一些步骤。

例子2:父母教孩子写作业

我们假设有一个父母教孩子写作业的场景,父母要求孩子按照以下步骤来写作业:

  1. 读懂题目。
  2. 划分大纲。
  3. 编写思维导图。
  4. 撰写正文。
  5. 检查错误并提交。

我们可以使用模板方法模式来实现这个例子。首先,我们定义一个抽象类 Homework,其中 doHomework() 方法是模板方法:

public abstract class Homework {

    // 模板方法
    public final void doHomework() {
        readQuestion();
        makeOutline();
        writeMindMap();
        writeContents();
        checkErrors();
    }

    void readQuestion() {
        System.out.println("Read the homework question");
    }

    void checkErrors() {
        System.out.println("Check errors and submit the homework");
    }

    abstract void makeOutline();

    abstract void writeMindMap();

    abstract void writeContents();
}

Homework 类中,我们定义了一个模板方法 doHomework(),在这个方法中,我们定义了几个步骤:readQuestion()makeOutline()writeMindMap()writeContents()checkErrors()

接下来,我们定义两个具体类 MathHomeworkEnglishHomework,这两个类分别对应数学作业和英语作业:

public class MathHomework extends Homework {

    void makeOutline() {
        System.out.println("Make an outline of the math homework");
    }

    void writeMindMap() {
        System.out.println("Write a mind map for the math homework");
    }

    void writeContents() {
        System.out.println("Write the contents of the math homework");
    }
}

public class EnglishHomework extends Homework {

    void makeOutline() {
        System.out.println("Make an outline of the English homework");
    }

    void writeMindMap() {
        System.out.println("Write a mind map for the English homework");
    }

    void writeContents() {
        System.out.println("Write the contents of the English homework");
    }
}

MathHomeworkEnglishHomework 类中,我们分别实现了 makeOutline()writeMindMap()writeContents() 三个抽象方法,这些方法将在 doHomework() 中被调用。

现在,我们可以使用这些类来教孩子写作业:

Homework mathHomework = new MathHomework();
mathHomework.doHomework();

Homework englishHomework = new EnglishHomework();
englishHomework.doHomework();

输出结果如下:

Read the homework question
Make an outline of the math homework
Write a mind map for the math homework
Write the contents of the math homework
Check errors and submit the homework

Read the homework question
Make an outline of the English homework
Write a mind map for the English homework
Write the contents of the English homework
Check errors and submit the homework

从输出结果可以看出,父母教孩子写数学作业和英语作业过程中,都共用了 Homework 类中定义的一些步骤。

总结

模板方法模式是一种常用的设计模式,它可以将具体实现延迟到子类中,从而使算法的骨架不会改变。在实际应用中,我们可以根据具体的场景,使用这种模式来提高代码的复用性和可维护性。

本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:Java设计模式之模板方法模式Template Method Pattern详解 - Python技术站

(0)
上一篇 2023年6月26日
下一篇 2023年6月26日

相关文章

  • java二叉树的非递归遍历

    下面我详细讲解一下Java二叉树的非递归遍历的完整攻略。 1. 什么是二叉树? 二叉树(Binary Tree)是一种树型的数据结构,它的每个节点最多只有两个子节点,分别称为左子节点和右子节点。 2. 如何遍历二叉树? 二叉树的遍历有三种方式:前序遍历、中序遍历和后序遍历。 前序遍历:先访问根节点,再遍历左子树和右子树。 中序遍历:先遍历左子树,再访问根节点…

    other 2023年6月27日
    00
  • SQL – 批量修改表中所有行数据某字段的部分内容

    以下是SQL-批量修改表中所有行数据某字段的部分内容的完整攻略,包括使用步骤和两个示例说明。 使用步骤 使用SQL批量修改表中所有行数据某字段的部分内容的步骤如下: 打开SQL客户端,连接到目标数据库。 编写SQL语句,使用UPDATE命令更新表中所有行数据某字段的部分内容。 使用WHERE子句指定要更新的行。 执行SQL语句,更新表中所有行数据某字段的部分…

    other 2023年5月7日
    00
  • Javascript通过控制类名更改样式

    下面是详细讲解 Javascript 通过控制类名更改样式的攻略。 什么是控制类名更改样式? 在网页开发中,我们经常需要对页面的样式进行管理和控制,而传统的做法通常是使用 JavaScript 直接操作样式属性。但这种做法不仅会使代码繁琐,而且在样式修改频繁的情况下难以维护。而通过控制类名更改样式,则是一种更加高效和可维护的做法,其基本思路是利用类名和 CS…

    other 2023年6月27日
    00
  • git-如何解决gitstatus“unmergedpaths:”?

    当在Git中执行git status命令时,有时会出现unmerged paths的提示,这意味着在合并分支时存在冲突。在本攻略中,我们将详细讲解如何决unmerged paths的问题,并提供两个示例说明。 解决方法 方法1:手动解决冲突 当Git提示merged paths时,我们需要手动解决冲突。首先,我们需要使用git status命令查看哪些文件存…

    other 2023年5月8日
    00
  • Mac实用操作技巧(二)

    Mac实用操作技巧(二) 如果你是一个Mac用户,你可能已经看到Mac已经有很好的易用性和用户友好的设计。但是,仍然有很多操作技巧可以帮助你在Mac上的工作效率更高。以下是一些Mac实用的操作技巧,可以帮助你节省时间和增加你的生产力。 1. 使用截图工具 Mac内置的截图工具可以迅速地截取你屏幕上的任意区域。你可以按住Command + Shift + 4,…

    其他 2023年3月28日
    00
  • KMP算法最浅显理解(小白教程)

    KMP算法最浅显理解(小白教程) 什么是KMP算法? KMP算法(Knuth-Morris-Pratt算法)是一种字符串匹配算法,用于在一个主串中查找一个模式串的出现位置。与朴素的字符串匹配算法相比,KMP算法具有更高的效率。 KMP算法的基本思想 KMP算法的基本思想是利用已经匹配过的部分信息,避免不必要的回溯。它通过构建一个部分匹配表(Partial M…

    other 2023年8月6日
    00
  • mysql 替换字段部分内容及mysql 替换函数replace()

    MySQL 是一个广泛使用的关系型数据库管理系统,其中提供了很多适用于数据处理的函数。replace() 函数是 MySQL 中的一种函数,它可以用来替换掉某个字符串中的一部分内容,常用于处理字符串型字段的内容更新。 一、replace() 函数的基本用法 replace() 函数的基本用法如下: replace(str,from_str,to_str) 其…

    other 2023年6月25日
    00
  • vue项目之webpack打包静态资源路径不准确的问题

    下面详细讲解 “vue项目之 webpack打包静态资源路径不准确的问题” 的攻略流程,如下: 问题描述 在使用 webpack 打包 vue 项目时,如果项目中使用了静态资源(如图片、字体等),在打包后访问页面时可能会出现静态资源路径不正确的问题。 解决方案 方案一:配置 publicPath 参数 webpack 提供了配置 publicPath 参数的…

    other 2023年6月27日
    00
合作推广
合作推广
分享本页
返回顶部