1.定义
在一个方法中定义一个算法的骨架,而将一些步骤延迟到子类中.模板方法使得子类可以在不改变算法结构的情况下,重新定义算法中的某些步骤. 简单来说就是抽象类中的一个 final 修饰的 方法封装了几个方法,而这些方法需要子类的具体实现,但是总体算法的步骤是抽象类中定义好的.
2.代码实现
这次模拟的是泡咖啡和泡茶两种行为,泡咖啡的步骤是 1.烧开水 2.冲泡咖啡粉 3. 咖啡倒进杯子 4. 加糖和牛奶
泡茶的步骤是 1.烧开水 2. 泡茶叶 3. 把茶倒进杯子 4. 加柠檬
这边相似的动作是 1 烧开水 和 3 倒进杯子 不同的是 一个泡的咖啡,加的是糖和牛奶,另一个是 泡的茶,加的是柠檬. 所以我们可以把 冲泡这个动作和加东西这个动作给抽象出来,具体的实现让子类进行.
这两种行为的步骤都是一致的,所以我们可以用一个抽象类来封装这种步骤.
public abstract class CaffeineBeverage { /** * 封装的步骤 */ final void prepareRecipe() { boilWater(); brew(); pourInCup(); if (customerWantsCondiments()) { addCondiments(); } } abstract void brew(); abstract void addCondiments(); void boilWater() { System.out.println("Biling water"); } void pourInCup() { System.out.println("Pouring into cup"); } /** * 钩子方法 * @return */ boolean customerWantsCondiments() { return true; } }
prepareRecipe 这个方法中 ,我们调用了 烧开水,冲泡,倒进杯子,加调料这四种方法,其中烧开水和倒进杯子这两种方法由抽象类实现,因为都是冲泡饮料相同的动作,不同的实现冲泡和加调料这两种方法,我们可以让具体的子类去实现. 而且prepareRecipe 方法是final类型的,就是防止子类覆盖这个方法修改方法的执行步骤.
customerWantsCondiments 方法是钩子方法,钩子方法在模板方法中可以当作一个条件来让子类决定算法的行为,子类可以选择实现或者选择不实现.
我们先定义茶
public class Tea extends CaffeineBeverage{ @Override void brew() { System.out.println("Steeping the tea"); } @Override void addCondiments() { System.out.println("Adding Lemon"); } }
茶这边实现了咖啡饮料这个抽象方法, 并且实现了 brew 和 addCondiments 这里两种抽象方法.
定义咖啡
public class Coffee extends CaffeineBeverage{ @Override void brew() { System.out.println("Dripping Coffee through filter"); } @Override void addCondiments() { System.out.println("Adding sugar and milk"); } @Override boolean customerWantsCondiments() { Scanner sc = new Scanner(System.in); String str = sc.nextLine(); if (str.toLowerCase().equals("y")) { return true; } return false; } }
咖啡也实现了 brew 和 addCondiments 这里两种抽象方法. 并且也实现了customerWantsCondiments方法,可以通过舒服 'Y' 或者 'N' 来让用户选择加糖和牛奶或者不加.这就是钩子的一个用途.
测试累
public class ModelTest { public static void main(String[] args) { Tea tea = new Tea(); tea.prepareRecipe(); System.out.println(); Coffee coffee = new Coffee(); coffee.prepareRecipe(); } }
执行结果
Biling water
Steeping the tea
Pouring into cup
Adding Lemon
Biling water
Dripping Coffee through filter
Pouring into cup
Y
Adding sugar and milk
这里输入了 Y 以后才加入了Adding Sugar and mikl
3.总结
我们可以看到模板方法主要是通过继承来实现的,在抽象类中定义了一个final方法来规定算法的具体框架,然后算法框架中的具体实现让子类去进行,所以这种需要子类实现的算法可以定义成 abstract 类型.
这里钩子这个方法因为是子类可以选择实现或者选择不实现的方法,所以没必要定义成abstract类型,主要是用来让子类实现这个方法改变算法的一些步骤.
和策略模式不同的是,模板方法是定义算法的框架,而策略模式是通过组合的方式来实现具体的算法.两者定位不同.
这边工厂模式也是通过子类来决定具体生成哪一种工厂模式,并且也是通过继承抽象类的方法来实现,所以也可以把工厂模式当作模板方法的变体.