chapter08_封装算法——模板方法模式

  • (1) 模板方法定义了一个算法的步骤, 并允许子类为一个或多个步骤提供实现

    (2) 示例

    CaffeineBeverage.java

      public abstract class CaffeineBeverage {
    
          final void prepareRecipe() {
    
              boilWater();
              
              brew();
      
              pourInCup();
      
              addCondiments();
          }
    
          abstract void brew();
    
          abstract void addCondiments();
    
          void boilWater() {
    
              System.out.println("Boiling water");
          }
    
          void pourInCup() {
    
              System.out.println("Pouring into cup");
          }
      }
    

    Coffee.java

      public class Coffee extends CaffeineBeverage {
    
          public void brew() {
    
              System.out.println("Dripping Coffee through filter");
          }
    
          public void addCondiments() {
    
              System.out.println("Adding Sugar and Milk");
          }
      }
    

    Tea.java

      public class Tea extends CaffeineBeverage {
    
          public void brew() {
    
              System.out.println("Steeping the tea");
          }
    
          public void addCondiments() {
    
              System.out.println("Adding Lemon");
          }
      }
    

    在基类CaffeineBeverage中定义了final方法prepareRecipe(), 因为咖啡因饮料的冲泡流程是固定的, 它内部分为4个步骤, 每个步骤抽象为一个方法;

    对于所有派生类都相同的boilWater()和pourInCup()方法在基类中给出默认实现, 对于个性化定制的方法定义为abstract由子类实现

  • 模板方法模式

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

  • 钩子hook

    (1) 有的时候派生类可能不是完全按照基类的final方法中所定义的步骤来, 在几个步骤之间可能还插入了其他步骤, 这是就要引入钩子hook

    (2) 示例

    CaffeineBeverageWithHook.java

      public abstract class CaffeineBeverageWithHook {
    
          final void prepareRecipe() {
    
              boilWater();
    
              hook();
              
              brew();
      
              pourInCup();
      
              addCondiments();
          }
    
          abstract void brew();
    
          abstract void addCondiments();
    
          void boilWater() {
    
              System.out.println("Boiling water");
          }
    
          void pourInCup() {
    
              System.out.println("Pouring into cup");
          }
    
          hook() {
          }
      }
    

    在boilWater()和brew()之间添加了一个方法hook(), 在基类中定义为空函数体; 如果子类需要添加步骤, 就可以覆盖hook()方法

    (3) 使用hook的原则

    当子类必须实现算法中的某个步骤时, 定义为abstract方法强制让子类实现;

    当某个部分不是必须时, 定义为hook增加灵活性

  • 设计原则: 好莱坞原则

    底层组件尽可能不要调用高层组件, 而是让高层组件去调用底层组件

注 

1° 这条原则的目的是避免高层组件和底层组件的环状依赖

2° 模板方法模式就体现了这个原则: 高层组件(基类)在需要的时候调用底层组件(派生类)的方法
  • 模板方法的实际应用

    (1) Arrays.sort()方法

      public static  void sort(T[] a, Comparator c);
    

    在sort方法中定义了一系列步骤, 具体怎么比较排序交给一个Comparator对象, 这个对象必须是T或者T的基类

    (2) Swing中的paint()方法

    paint()方法在Component类中定义为hook空函数, 子类中定义它的具体实现决定如何绘图

      public class MyFrame extends JFrame {
    
          public void paint(Graphics graphics) {
    
              super.paint(graphics);
              
              String msg = "I rule!!";
    
              graphics.drawString(msg, 100, 100);
          }
    
          ...
      }
    
  • 模板方法模式和策略模式的比较

    (1) 模板方法模式定义一个算法大纲, 由子类实现其中某些步骤;

    策略模式定义一个算法家族, 并让算法之间可以互相替换

    (2) 模板方法使用了继承(因为算法中的很多步骤是相同的);

    策略模式使用了组合

  • 为了防止子类修改模板方法中的算法, 可以声明方法为final, 同时引入hook增加灵活性

  • 工厂方法模式可以理解为模板方法模式的一个特例(算法的其中一步创建某个需要的对象实例时交给子类实现)

你可能感兴趣的:(chapter08_封装算法——模板方法模式)