标签:使用 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。
进一步分析,两种冲泡法其实都用了相同的算法:
所以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