设计模式:模板方法模式

意图

模板方法模式Template Method是一种行为设计模式 它在超类中定义了一个算法的框架 允许子类在不修改结构的情况下重写算法的特定步骤

解决方案

模板方法模式建议将算法分解为一系列步骤 然后将这些步骤改写为方法 最后在 模板方法 中依次调用这些方法 步骤可以是 抽象 也可以有一些默认的实现 为了能够使用算法 客户端需要自行提供子类并实现所有的抽象步骤 如有必要还需重写一些步骤 但这一步中不包括模板方法自身

 模板方法模式结构

模板方法设计模式的结构

抽象类 Abstract­Class 会声明作为算法步骤的方法 以及依次调用它们的实际模板方法 算法步骤可以被声明为 抽象类型 也可以提供一些默认实现

具体类 Concrete­Class) 可以重写所有步骤, 但不能重写模板方法自身。

模板方法模式适合应用场景

  • 当你只希望客户端扩展某个特定算法步骤 而不是整个算法或其结构时 可使用模板方法模式

模板方法将整个算法转换为一系列独立的步骤 以便子类能对其进行扩展 同时还可让超类中所定义的结构保持完整

  • 当多个类的算法除一些细微不同之外几乎完全一样时 你可使用该模式 但其后果就是 只要算法发生变化 你就可能需要修改所有的类

在将算法转换为模板方法时 你可将相似的实现步骤提取到超类中以去除重复代码 子类间各不同的代码可继续保留在子类中

模板方法模式优缺点

优点:

  •  你可仅允许客户端重写一个大型算法中的特定部分 使得算法其他部分修改对其所造成的影响减小
  •  你可将重复代码提取到一个超类中

缺点:

  •  部分客户端可能会受到算法框架的限制
  •  通过子类抑制默认步骤实现可能会导致违反_里氏替换原则_
  •  模板方法中的步骤越多 其维护工作就可能会越困难

与其他模式的关系

  • 工厂方法模式模板方法模式的一种特殊形式 同时 工厂方法可以作为一个大型模板方法中的一个步骤

  • 模板方法基于继承机制 它允许你通过扩展子类中的部分内容来改变部分算法 策略模式基于组合机制 你可以通过对相应行为提供不同的策略来改变对象的部分行为 模板方法在类层次上运作 因此它是静态的 策略在对象层次上运作 因此允许在运行时切换行为

在 Java 中使用模式

使用示例 模版方法模式在 Java 框架中很常见 开发者通常使用它来向框架用户提供通过继承实现的 对标准功能进行扩展的简单方式

这里是一些核心 Java 程序库中模版方法的示例

示例代码

public abstract class Game {

  abstract void initialize();

  abstract void startPlay();

  abstract void endPlay();

  public final void play() {
    initialize();
    startPlay();
    endPlay();
  }
}
public class Cricket extends Game {
  @Override
  void endPlay() {
    System.out.println("Cricket Game Finished!");
  }

  @Override
  void initialize() {
    System.out.println("Cricket Game Initialized! Start playing.");
  }

  @Override
  void startPlay() {
    System.out.println("Cricket Game Started. Enjoy the game!");
  }
}
public class Football extends Game {
  @Override
  void endPlay() {
    System.out.println("Football Game Finished!");
  }

  @Override
  void initialize() {
    System.out.println("Football Game Initialized! Start playing.");
  }

  @Override
  void startPlay() {
    System.out.println("Football Game Started. Enjoy the game!");
  }
}
public class Client {
  public static void main(String[] args) {
    Game game = new Cricket();
    game.play();
    System.out.println();
    game = new Football();
    game.play();
  }
}