模式定义
在一个方法中定义一个算法的骨架,而将一些步骤延迟到子类中。模版方法使得子类可以在不改变算法结构的情况下,重新定义算法中的某些步骤。
模式理解
简单来说就是,模版中定好步骤并实现基本方法,子类实现特定方法。
需要注意的地方:模版方法需要使用final标记以防止其它方法对模版做改动,模版方法的基本实现需要标记为private使得其子类不能修改模版类的最基本实现,模版方法中可拓展实现需标记为抽象的并且为protected。使得只有子类才能实现其可变方法。
模式例子
以冲泡咖啡或茶为例,实现模版方法。
泡咖啡步骤:把水煮沸,冲泡,把饮料倒进杯子,加调料。
泡茶步骤:把水煮沸,用沸水浸泡茶叶,把茶倒进杯子。
模版抽象类(RefreshBeverage.java)
package com.pattern.template; /* * 抽象基类,为所有子类提供一个算法框架 * * 提神饮料 */ public abstract class RefreshBeverage { /* * 制备饮料的模板方法 * 封装了所有子类共同遵循的算法框架 */ public final void prepareBeverageTemplate(){ //步骤1 将水煮沸 boilWater(); //步骤2 泡制饮料 brew(); //步骤3 将饮料倒入杯中 pourInCup(); if(isCustomerWantsCondiments()){ //步骤4 加入调味料 addCondiments(); } } /* * Hook, 钩子函数,提供一个默认或空的实现 * 具体的子类可以自行决定是否挂钩以及如何挂钩 * 询问用户是否加入调料 */ protected boolean isCustomerWantsCondiments() { return true; } /* * 基本方法,将水煮沸 */ private void boilWater() { System.out.println("将水煮沸"); } /* * 基本方法,将饮料倒入杯中 */ private void pourInCup() { System.out.println("将饮料倒入杯中"); } /* * 抽象的基本方法,泡制饮料 */ protected abstract void brew(); /* * 抽象的基本方法, 加入调味料 */ protected abstract void addCondiments(); }
咖啡类(Coffee.java)
package com.imooc.pattern.template; /* * 具体子类,提供了咖啡制备的具体实现 */ public class Coffee extends RefreshBeverage { @Override protected void brew() { System.out.println("用沸水冲泡咖啡"); } @Override protected void addCondiments() { System.out.println("加入糖和牛奶"); } }
茶类(Tea.java)
package com.pattern.template; /* * 具体子类,提供了制备茶的具体实现 */ public class Tea extends RefreshBeverage { @Override protected void brew() { System.out.println("用80度的热水浸泡茶叶5分钟"); } @Override protected void addCondiments() { System.out.println("加入柠檬"); } @Override /* * 子类通过覆盖的形式选择挂载钩子函数 * @see com.imooc.pattern.template.RefreshBeverage#isCustomerWantsCondiments() */ protected boolean isCustomerWantsCondiments(){ return false; } }
测试类(RefreshBeverageTest.java)
package com.pattern.template; public class RefreshBeverageTest { public static void main(String[] args) { System.out.println("制备咖啡..."); RefreshBeverage b1 = new Coffee(); b1.prepareBeverageTemplate(); System.out.println("咖啡好了!"); System.out.println("\n******************************************"); System.out.println("制备茶..."); RefreshBeverage b2 = new Tea(); b2.prepareBeverageTemplate(); System.out.println("茶好了!"); } }
模式适用场景
算法或操作遵循相同的逻辑;
重构中提取相同功能代码做成模版;
重要或复杂的代码。
模式优缺点
优点:封装性好,复用性好,屏蔽细节,便于维护。
缺点:继承,已经有继承的类不好做模版方法的重构。