正文

一、定义

模板方法模式在一个方法中定义一个算法的骨架,而将一些步骤延迟到子类中。模板方法使得子类可以在不改变算法结构的情况下,重新定义算法中的某些步骤。

要点:

  • 模板方法定义了一个算法的步骤,每个步骤都被一个方法所代表,而这几个方法的具体实现可由子类提供。
  • 模板方法可确保算法的结构保持不变,同时由子类提供部分实现。

二、实现步骤

1、创建一个抽象类,并定义模板方法

模板方法一般声明为 final,以免子类改变算法的步骤。

抽象类中,可以声明一些钩子方法,子类视情况决定要不要覆盖它们。钩子的存在,可以让子类有能力对算法的不同点进行挂钩,使得模板方法更具有弹性。

/**
* 抽象类
*/
public abstract class AbstractClass { /**
* 模板方法
*/
public final void templateMethod() {
// 公共步骤,由抽象类实现
commonStep();
// 依赖于子类的步骤,由子类实现
step1();
step2();
step3();
// 钩子方法,由子类决定要不要覆盖
hook();
} /**
* 步骤1
*/
public abstract void step1(); /**
* 步骤2
*/
public abstract void step2(); /**
* 步骤3
*/
public abstract void step3(); /**
* 公共步骤
*/
private void commonStep() {
System.out.println("I'm common step!");
} /**
* 钩子方法
*/
public void hook() {
// 可以空实现,也可以提供默认实现
}
}

2、创建具体子类,并提供算法步骤的具体实现

(1)具体子类A

/**
* 具体子类A
*/
public class ConcreteClassA extends AbstractClass{ @Override
public void step1() {
System.out.println("I'm step A1!");
} @Override
public void step2() {
System.out.println("I'm step A2!");
} @Override
public void step3() {
System.out.println("I'm step A3!");
} @Override
public void hook() {
System.out.println("I'm hook step A!");
}
}

(2)具体子类B

/**
* 具体子类B
*/
public class ConcreteClassB extends AbstractClass{ @Override
public void step1() {
System.out.println("I'm step B1!");
} @Override
public void step2() {
System.out.println("I'm step B2!");
} @Override
public void step3() {
System.out.println("I'm step B3!");
}
}

3、通过使用不同的子类,来确定具体的算法步骤

public class Test {

    public static void main(String[] args) {
AbstractClass classA = new ConcreteClassA();
classA.templateMethod();
System.out.println();
AbstractClass classB = new ConcreteClassB();
classB.templateMethod();
}
}

三、举个栗子

1、背景

《星巴兹咖啡师傅训练手册》规定了,准备星巴兹饮料时,必须精确地遵循下面的冲泡法:

星巴兹咖啡冲泡法:

  1. 把水煮沸
  2. 用沸水冲泡咖啡
  3. 把咖啡倒进杯子
  4. 加糖和牛奶

星巴兹茶冲泡法:

  1. 把水煮沸
  2. 用沸水浸泡茶叶
  3. 把茶倒进杯子
  4. 加柠檬

现在,让我们扮演“代码师傅”,写一些代码来创建咖啡和茶。

2、实现

(1)创建咖啡因饮料抽象类,并定义冲泡步骤的方法

/**
* 咖啡因饮料抽象类
*/
public abstract class CaffeineBeverage { /**
* 准备冲泡法(模板方法)
*/
final void prepareRecipe() {
boilWater();
brew();
pourInCup();
if (customerWantsCondiments()) {
addCondiments();
}
} /**
* 冲泡(依赖于子类的步骤)
*/
abstract void brew(); /**
* 添加调料(依赖于子类的步骤)
*/
abstract void addCondiments(); /**
* 烧水(公共步骤)
*/
void boilWater() {
System.out.println("Boiling water");
} /**
* 把饮料倒进杯子(公共步骤)
*/
void pourInCup() {
System.out.println("Pouring into cup");
} /**
* 顾客是否想要添加调料(钩子方法)
*/
boolean customerWantsCondiments() {
return true;
}
}

(2)创建具体的饮料,并提供具体冲泡步骤的实现

/**
* 咖啡
*/
public class Caffee extends CaffeineBeverage{ @Override
void brew() {
System.out.println("Dripping Coffee through filter");
} @Override
void addCondiments() {
System.out.println("Adding Sugar and Milk");
} @Override
boolean customerWantsCondiments() {
String answer = askCustomer();
if (answer.toLowerCase().startsWith("y")) {
return true;
} else {
return false;
}
} /**
* 询问顾客
*/
private String askCustomer() {
System.out.print("Would you like milk and suger with your coffee (y/n)?");
String answer = null;
Scanner scanner = new Scanner(System.in);
if (scanner.hasNext()) {
answer = scanner.nextLine();
}
scanner.close();
if (answer == null) {
return "no";
}
return answer;
}
}
/**
* 茶
*/
public class Tea extends CaffeineBeverage{ @Override
void brew() {
System.out.println("Steeping the tea");
} @Override
void addCondiments() {
System.out.println("Adding Lemon");
}
}

(3)冲泡饮料

public class Test {

    public static void main(String[] args) {
// 茶
System.out.println("\nMaking tea...");
CaffeineBeverage tea = new Tea();
tea.prepareRecipe();
// 咖啡
System.out.println("\nMaking coffee...");
CaffeineBeverage caffee = new Caffee();
caffee.prepareRecipe();
}
}

《Head First 设计模式》:模板方法模式的更多相关文章

  1. linkin大话设计模式--模板方法模式

    linkin大话设计模式--模板方法模式 准备一个抽象类,将部分逻辑以具体方法的形式实现,然后申明一些抽象方法来迫使子类实现剩余的逻辑.不同的子类可以以不同的方式实现这些抽象方法,从而对剩余的逻辑有不 ...

  2. 结合JDK源码看设计模式——模板方法模式

    前言: 相信很多人都听过一个问题:把大象关进冰箱门,需要几步? 第一,把冰箱门打开:第二,把大象放进去:第三,把冰箱门关上.我们可以看见,这个问题的答案回答的很有步骤.接下来我们介绍一种设计模式--模 ...

  3. 瑞幸咖啡还是星巴克,一杯下午茶让我明白 设计模式--模板方法模式(Template Method Pattern)

    简介 Define the skeleton of an algorithm in an operation,deferring some steps to subclasses.Template M ...

  4. C#设计模式-模板方法模式

    提到模板,大家肯定不免想到生活中的“简历模板”.“论文模板”.“Word中模版文件”等,在现实生活中,模板的概念就是——有一个规定的格式,然后每个人都可以根据自己的需求或情况去更新它,例如简历模板,下 ...

  5. java设计模式 模板方法模式Template Method

    设计模式(Design pattern)是一套被反复使用.多数人知晓的.经过分类编目的.代码设计经验的总结.使用设计模式是为了可重用代码.让代码更容易被他人理解.保证代码可靠性.毫无疑问,设计模式于己 ...

  6. JAVA 设计模式 模板方法模式

    定义 模板方法模式 (Template Method) 定义了一个操作中的算法的骨架,而将部分步骤的实现在子类中完成. 模板方法模式使得子类可以不改变一个算法的结构即可重定义该算法的某些特定步骤. 模 ...

  7. 深入浅出设计模式——模板方法模式(Template Method Pattern)

    模式动机 模板方法模式是基于继承的代码复用基本技术,模板方法模式的结构和用法也是面向对象设计的核心之一.在模板方法模式中,可以将相同的代码放在父类中,而将不同的方法实现放在不同的子类中.在模板方法模式 ...

  8. 设计模式-模板方法模式(Head First)

    参考书籍:Head First设计模式 什么是模板方法模式 定义:在一个方法中定义一个算法的骨架,而将一些步骤延迟到子类中.模板方法使得子类可以在不改变算法结构的情况下,重新定义算法中的某些步骤. 怎 ...

  9. javascript设计模式——模板方法模式

    前面的话 在javascript开发中用到继承的场景其实并不是很多,很多时候喜欢用mix-in的方式给对象扩展属性.但这不代表继承在javascript里没有用武之地,虽然没有真正的类和继承机制,但可 ...

  10. C++设计模式——模板方法模式

    模板方法模式 在GOF的<设计模式:可复用面向对象软件的基础>一书中对模板方法模式是这样说的:定义一个操作中的算法骨架,而将一些步骤延迟到子类中.TemplateMethod使得子类可以不 ...

随机推荐

  1. Skill 返回一个数字list的大小排序信息

    https://www.cnblogs.com/yeungchie/ code procedure(ycSortList(numlist) prog((size sort) foreach(main ...

  2. GPS坐标显示在百度地图上(Qt+百度地图)

    Qt在5.6以后的版本就不支持webview控件了,这里我用的是Qt5.4的版本,里面还有这个控件: 下面简单介绍下Qt与html中的javascript调用交互过程: 一.整体实现介绍 在html中 ...

  3. 如何查看Docker容器环境变量,如何向容器传递环境变量

    1 前言 欢迎访问南瓜慢说 www.pkslow.com获取更多精彩文章! 了解Docker容器的运行环境非常重要,我们把应用放在容器里执行,环境变量会直接影响程序的执行效果.所以我们要知道容器内部的 ...

  4. NIO(二):Channel通道

    一.Channel概述 channel(通道):进行IO的连接通道,为NIO的几个核心(Buffer,selector,channel)之一,相比于IO的stream具有较高的性能. IO 单向传输 ...

  5. 18、Memento 备忘录模式

    例如:用于记录快照(顺势状态).存盘 1.Memento Memento设计模式是一种软件设计模式,用于将对象回滚到其先前状态.它是行为设计模式的一部分,与算法和对象之间的职责分配有关. 行为模式描述 ...

  6. Nginx安装与运行配置总结

    Nginx安装与运行配置总结 1. 去官网下载对应的nginx包,推荐使用稳定版本 2. 上传nginx到linux系统 3. 安装依赖环境 (1)安装gcc环境 yun install gcc-c+ ...

  7. CSS动画实例:一颗躁动的心

    在页面中放置一个类名为container的层作为盛放心心的容器,在该层中再定义一个名为heart的子层,HTML代码描述如下: <div class="container"& ...

  8. [Hadoop] mapper数量的控制

    确定map任务数时依次优先参考如下几个原则: 1)      每个map任务使用的内存不超过800M,尽量在500M以下 比如处理256MB数据需要的时间为10分钟,内存为800MB,此时如果处理12 ...

  9. linux手动安装python

    前提:你的linux服务器必须有gcc编译器,gcc查看方法:linux命令行>gcc -v 如果返回版本信息证明已经安装, 如果找不到命令,跳到这篇手动安装gcc >>> l ...

  10. int ,long , long long , __int64类型的范围

    首先见测试代码(在g++/gcc下运行): #include<iostream> using namespace std; int main() { cout<<sizeof( ...