定义

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

  • 模板方法定义了一个算法的步骤, 并允许子类为一个或多个步骤提供实现
  • java的数组的排序就使用了模板方法模式, 需要排序的对象需要实现Comparable接口或是重写方法
  • java的io的InputStream类的read()方法, 是由子类实现, 而这个方法又会被read(byte b[], int off, int len)模板方法使用
  • 策略模式组合的类实现了整个算法, 而模板方法允许子类补充实现
  • 模板方法的抽象类可以定义具体方法, 抽象方法, 和钩子, 钩子是一种方法, 它在抽象类中不做事, 或者只做默认的事情, 子类可以选择要不要去覆盖它

模板方法模式与策略模式的比较
1.策略模式定义一个算法家族, 并让这些算法可以互换, 因为每一个算法都被封装起来了, 所以客户可以轻易的使用不同的算法
2.模板方法模式定义了一个算法的大纲, 由子类定义其中某些步骤的内容, 这样算法中的不同步骤可以有不同的实现细节, 但算法的结构依然维持不变
3.策略模式使用的是对象组合, 模板方法使用的是继承抽象类

设计原则:

  • 好莱坞原则: 别调用(打电话)我们, 我们会调用(打电话)你

在好莱坞原则之下, 我们允许低层组件将自己挂钩到系统上, 但是高层组件会决定什么时候和怎样使用这些低层组件
image.png

案例

背景:设计类来描述茶和咖啡冲调的步骤, 并抽取共同的代码
茶冲调的步骤:1.煮开水;2.冲泡茶;3.倒入杯中;4.加柠檬
咖啡冲调的步骤:1.煮开水;2.冲泡咖啡;3.倒入杯中;4.加糖和牛奶

image.png
基类, 设计prepareRecipe模板方法, 并声明为final不让子类重写;
相同的部分在基类中实现, 不同的部分声明为抽象方法, 由子类实现

  1. public abstract class CaffeineBeverage {
  2. final void prepareRecipe() {
  3. boilWater();
  4. brew();
  5. pourInCup();
  6. addCondiments();
  7. }
  8. private void boilWater() {
  9. System.out.println("煮开水");
  10. }
  11. abstract void brew();
  12. private void pourInCup() {
  13. System.out.println("倒入杯中");
  14. }
  15. abstract void addCondiments();
  16. }

  1. public class Tea extends CaffeineBeverage {
  2. @Override
  3. void brew() {
  4. System.out.println("冲泡茶");
  5. }
  6. @Override
  7. void addCondiments() {
  8. System.out.println("加柠檬");
  9. }
  10. }

咖啡

  1. public class Coffee extends CaffeineBeverage {
  2. @Override
  3. void brew() {
  4. System.out.println("冲泡咖啡");
  5. }
  6. @Override
  7. void addCondiments() {
  8. System.out.println("加糖和牛奶");
  9. }
  10. }

设计原则分析:
image.png