JAVA 设计模式 模板方法模式

定义

模板方法模式 (Template Method)

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

模板方法模式是所有模式中最为常见的几个模式之一,是基于继承代码复用的基本技术。,没有关联关系。

因此,在模板方法模式的类结构图中,只有继承关系

模板方法模式需要开发抽象类和具体子类的设计师之间的协作。一个设计师负责给出一个算法的轮廓和骨架,另一些设计师则负责给出这个算法的各个逻辑步骤。

代表这些具体逻辑步骤的方法称做基本方法(primitive method);而将这些基本方法汇总起来的方法叫做模板方法(template method),这个设计模式的名字就是从此而来。

结构

图-模板方法模式结构图

AbstractClass : 抽象类,定义并实现一个模板方法。这个模板方法定义了算法的骨架,而逻辑的组成步骤在相应的抽象操作中,推迟到子类去实现。顶级逻辑也有可能调用一些具体方法。

abstract class AbstractClass {
 public abstract void PrimitiveOperation1();
 public abstract void PrimitiveOperation2();
 
 public void TemplateMethod() {
         PrimitiveOperation1();
         PrimitiveOperation2();
     }
 }

ConcreteClass : 实现实现父类所定义的一个或多个抽象方法。

class ConcreteClassA extends AbstractClass {
     @Override
 public void PrimitiveOperation1() {
         System.out.println("具体A类方法1");
     }
 
     @Override
 public void PrimitiveOperation2() {
         System.out.println("具体A类方法2");
     }
 }
 
 class ConcreteClassB extends AbstractClass {
     @Override
 public void PrimitiveOperation1() {
         System.out.println("具体B类方法1");
     }
 
     @Override
 public void PrimitiveOperation2() {
         System.out.println("具体B类方法2");
     }    
 }

测试代码

public class TemplateMethodPattern {
 public static void main(String[] args) {
         AbstractClass objA = new ConcreteClassA();
         AbstractClass objB = new ConcreteClassB();    
         objA.TemplateMethod();
         objB.TemplateMethod();
     }
 }

要点

模板方法模式中的三类角色 1、具体方法(Concrete Method)

2、抽象方法(Abstract Method)

3、钩子方法(Hook Method)

三类角色的关联

在模板方法模式中,首先父类会定义一个算法的框架,即实现算法所必须的所有方法。

其中,具有共性的代码放在父类的具体方法中。

各个子类特殊性的代码放在子类的具体方法中。但是父类中需要有对应抽象方法声明。

钩子方法可以让子类决定是否对算法的不同点进行挂钩。

总结

使用模板方法模式可以将代码的公共行为提取,以达到复用的目的。

而对于特殊化的行为在子类中实现。父类的模板方法可以控制子类中的具体实现。

子类无需了解整体算法框架,只需实现自己的业务逻辑即可。

实例

模板方法模式应用场景十分广泛。

在《Head First》的模板方法模式章节里列举了一个十分具有代表性的例子。 

现实生活中,茶和咖啡是随处可见的饮料。冲泡一杯茶或冲泡一杯咖啡的过程是怎样的?

我们来整理一下流程。

泡茶: 烧开水 ==> 冲泡茶叶 ==> 倒入杯中 ==> 添加柠檬 泡咖啡: 烧开水 ==> 冲泡咖啡 ==> 倒入杯中 ==> 添加糖和牛奶

由以上处理步骤不难发现,准备这两种饮料的处理过程非常相似。我们可以使用模板类方法去限定制作饮料的算法框架。

其中相同的具有共性的步骤(如烧开水、倒入杯中),直接在抽象类中给出具体实现。

而对于有差异性的步骤,则在各自的具体类中给出实现。

抽象类

abstract class Beverage {
 
 // 模板方法,决定了算法骨架。相当于TemplateMethod()方法
  public void prepareBeverage() {
         boilWater();
         brew();
         pourInCup();
 if (customWantsCondiments())
         {
             addCondiments();
         }
     }
 
 // 共性操作,直接在抽象类中定义
  public void boilWater() {
         System.out.println("烧开水");
     }
 
 // 共性操作,直接在抽象类中定义
  public void pourInCup() {
         System.out.println("倒入杯中");
     }
 
 // 钩子方法,决定某些算法步骤是否挂钩在算法中
  public boolean customWantsCondiments() {
 return true;
     }
 
 // 特殊操作,在子类中具体实现
  public abstract void brew();
 
 // 特殊操作,在子类中具体实现
  public abstract void addCondiments();
 
 }

具体类

class Tea extends Beverage {
 
     @Override
 public void brew() {
         System.out.println("冲泡茶叶");
     }
 
     @Override
 public void addCondiments() {
         System.out.println("添加柠檬");
     }
 
 }
 
 class Coffee extends Beverage {
 
     @Override
 public void brew() {
         System.out.println("冲泡咖啡豆");
     }
 
     @Override
 public void addCondiments() {
         System.out.println("添加糖和牛奶");
     }
 
 }

测试代码

public static void main(String[] args) {
 
     System.out.println("============= 准备茶 =============");
     Beverage tea = new Tea();
     tea.prepareBeverage();
 
     System.out.println("============= 准备咖啡 =============");
     Beverage coffee = new Coffee();
     coffee.prepareBeverage();
 
 }

运行结果

============= 准备茶 =============
 烧开水
 冲泡茶叶
 倒入杯中
 添加柠檬
 ============= 准备咖啡 =============
 烧开水
 冲泡咖啡豆
 倒入杯中
 添加糖和牛奶

推荐

本文属于 JAVA设计模式系列

参考资料

《大话设计模式》 《HeadFirst设计模式》

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏令仔很忙

观察者模式和Spring的结合

这周给分了一个任务,就是对查询回来的数据进行各种各样的过滤,有七种不同的过滤条件。过滤条件是在数据库中存着的。在我们项目中有一个热发,就是定时的从数据库中把数...

332
来自专栏柠檬先生

你不知道的javaScript笔记(3)

对象 对象可以通过两种形式定义: 声明形式和构造形式 声明形式语法: var myObj = {key:value} 构造形式语法: var myObj = n...

1745
来自专栏C/C++基础

设计模式 (5)——工厂方法模式(Factory Method,创建型)

使用设计模式可以提高代码的可复用性、可扩充性和可维护性。工厂方法模式(Factory Method Pattern)属于创建型模式,定义一个创建对象的接口函数,...

521
来自专栏一个会写诗的程序员的博客

《Kotlin 程序设计》第六章 Kotlin 函数式编程(FP)第六章 Kotlin 函数式编程(FP)1. 函数式编程概述2. Kotlin函数式编程参考资料

从本质上来说, 程序就是一系列有序执行的指令集合。 如何将指令集合组织成可靠可用可信赖的软件(美妙的逻辑之塔), 这是个问题。

946
来自专栏哲学驱动设计

绑定子类的泛型基类,反模式?

    这次总结一个个人认为的反模式:“绑定子类的泛型层基类”,这个模式在一些著名的框架中也见到过,如果CSLA、BlogEngine。我自己在原来的写的框架中...

1755
来自专栏海天一树

小朋友学C语言(17):斐波那契数列的递归实现

什么是递归呢?先举个例子: 从前有座山,山里有座庙,庙里有个老和尚,正在给小和尚讲故事呢!故事是什么呢?"从前有座山,山里有座庙,庙里有个老和尚,正在给小和尚讲...

2578
来自专栏zhisheng

干货分享:让你分分钟学会 javascript 闭包 一像素

闭包,是 javascript 中重要的一个概念,对于初学者来讲,闭包是一个特别抽象的概念,特别是ECMA规范给的定义,如果没有实战经验,你很难从定义去理解它。...

3295
来自专栏一个会写诗的程序员的博客

React极简教程: Hello,World!React简史React安装Hello,World

A programming paradigm is a fundamental style of computer programming. There are...

691
来自专栏一个会写诗的程序员的博客

第4章 类与面向对象编程第4章 类与面向对象编程

在前面的章节中,我们学习了Kotlin的语言基础知识、类型系统等相关的知识。在本章节以及下一章中,我们将一起来学习Kotlin对面向对象编程以及函数式编程的支持...

712
来自专栏屈定‘s Blog

设计模式--装饰者模式思考

装饰者模式实际上是一直提倡的组合代替继承的实践方式,个人认为要理解装饰者模式首先需要理解为什么需要组合代替继承,继承又是为什么让人深恶痛绝.

702

扫码关注云+社区