码迷,mamicode.com
首页 > 其他好文 > 详细

设计模式之模板方法

时间:2019-10-06 15:17:55      阅读:99      评论:0      收藏:0      [点我收藏+]

标签:使用   add   地方   sans   sys   name   sha   定义   ant   

一、前言

  最近复习发现AQS使用了模板方法,自定义同步器时需要重写几个AQS提供的模板方法,Spring的DefaultBeanDefinitionDocumentReader#doRegisterBeanDefinitions() 方法也使用了该设计模式,于是写篇文章加深理解。

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

单看这句话可能还没搞懂这个设计模式是干嘛的,下面看一个例子。

二、示例

不用设计模式,冲咖啡和泡茶的两个类分别是下面这样的。

public class Coffee {

  // 冲泡咖啡的算法
   void prepareRecipe(){
    boilWater();
    // 用沸水冲泡咖啡
    brewCoffeeGrinds();
    pourInCup();
    // 加牛奶和糖
    addSugarAndMilk();
  }

  private void addSugarAndMilk() {
  }

  private void pourInCup() {
  }

  private void brewCoffeeGrinds() {
  }

  private void boilWater() {
  }
}


public class Tea {

  // 泡茶的算法
  void prepareRecipe(){
    boilWater();
    // 用沸水浸泡茶叶
    steepTeaBag();
    pourInCup();
    // 加柠檬
    addLemon();
  }

  private void addLemon() {

  }

  private void pourInCup() {

  }

  private void steepTeaBag() {

  }

  private void boilWater() {

  }
}

很容易就可以发现这两个类中有重复代码,boilWater()和pourInCup()都重复了可以提取出来,因为茶和饮料都是咖啡饮料可以定义一个超类CaffeineBeverage。
进一步分析,两种冲泡法其实都用了相同的算法:

  1. 把水煮沸
  2. 用热水泡咖啡或茶
  3. 把饮料倒进杯子
  4. 在饮料里加调料

所以prepareRecipe()也可以抽象成一个,如下:

final void prepareRecipe(){
    boilWater();
    // 交给对应的子类实现
    brew();
    pourInCup();
    // 交给对应的子类实现
    addCondiments();
  }

最后,重构后的代码如下。

咖啡因饮料超类

public abstract class CaffeineBeverage {

  /**
   * 模板方法
   * 定义的算法步骤
   */
  final void prepareRecipe(){
    boilWater();
    brew();
    pourInCup();
    addCondiments();
  }

  /**
   * 添加调料
   */
  protected abstract void addCondiments();


  /**
   * 冲泡
   */
  protected abstract void brew();

  /**
   * 煮开水
   */
  private void boilWater() {
    System.out.println("Boiling water");
  }

  /**
   * 把饮料倒进杯子
   */
  private void pourInCup() {
    System.out.println("Pouring in cup");
  }

}

Tea

public class Tea extends CaffeineBeverage {

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

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

Coffee

public class Coffee extends CaffeineBeverage {

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

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

代码的类图就变成了下面的样子。

 

技术图片
类图

 

道理我懂,可是使用了模板方法模式之后有什么好处吗?

原本的实现模板方法后的实现
Coffee和Tea之间存在重复代码 CaffeineBeverage类实现了代码复用最大化
Coffee和Tea控制了算法 由CaffeineBeverage类主导一切,拥有并保护算法
对算法所做的代码改变,需要修改子类很多地方 算法只存在一个地方,很容易修改
算法的知识和它的实现分散在许多类中 CaffeineBeverage类专注算法本身,而由子类提供完整的实现

三、总结

设计模式这么多种,要做到灵活运用还真是长路漫漫啊。

设计模式之模板方法

标签:使用   add   地方   sans   sys   name   sha   定义   ant   

原文地址:https://www.cnblogs.com/2YSP/p/11627282.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!