模板方法模式
定义一个操作中的算法的骨架,而将一些步骤延迟到子类中。 模板方法使得子类可以不改变一个算法的结构即可重定义该算法的某些特定步骤。通俗的说的就是有很多相同的步骤的,在某一些地方可能有一些差别适合于这种模式,例如想要泡一杯茶或者一杯咖啡,第一步都是将水煮沸,第二部是加入咖啡或者茶,第三部就是将饮料倒入杯子中,第四部就是加入各种调味料。其中第一步和第三部都是一样的,这个就可以定义在基类,而第二步和第四步就是他们之间的差异就可以在具体的子类中去实现。下面就是代码实现。
定义抽象基类,为所有子类提供一个算法框架
public abstract class RereshBaverage { /** * 制备饮料的模板方法 * 封装了所有子类共同遵守的算法骨架 */ public final void prepreBvergeTemplage(){ //步骤一 将水煮沸 boilWater(); //步骤二 炮制饮料 brew(); //步骤三 将饮料倒入杯中 pourInCup(); //步骤四 加入调味料 addCondiments(); } /** * 基本方法,将水煮沸 这对所有子类而言是一个共同的行为,所以声明为private,无需向子类开放 */ private void boilWater(){ System.out.println("将水煮沸"); } /** * 抽象的基本方法 泡制饮料 * 在算法框架中并不知道具体实现是什么样子的,所以做成了抽象方法,并且由于我们需要在子类中可见,便于复写而提供具体的实现所以将 * 权限设置为protected */ protected abstract void brew(); private void pourInCup(){ System.out.println("将饮料倒入杯中"); } /** * 加入调味料 */ protected abstract void addCondiments(); }
具体子类,提供了咖啡制备的具体实现
public class Coffee extends RereshBaverage { @Override protected void brew() { System.out.println("用沸水冲泡咖啡"); } @Override protected void addCondiments() { System.out.println("加入糖和牛奶"); } }
具体子类,提供了制备茶的具体实现
public class Tea extends RereshBaverage { @Override protected void brew() { System.out.println("用80 度的热水浸泡茶叶5分钟"); } @Override protected void addCondiments() { System.out.println("加入柠檬"); } }
测试类
public class RereshBaverageTest { public static void main(String[] args) { System.out.println("咖啡制备中。。。"); RereshBaverage coffee = new Coffee(); coffee.prepreBvergeTemplage(); System.out.println("咖啡制备完成! "); System.out.println(" *********************"); System.out.println("茶制备中。。。"); RereshBaverage tea = new Tea(); tea.prepreBvergeTemplage(); System.out.println("茶制备完成!"); } }
运行结果:
如果我们希望喝到一杯black coffee或者喝到一杯纯正的茶,就是不希望实现第四个步骤,那么将如何实现呢,如何做到个性化的扩展呢,这里就用到了一个钩子方法。
改造基类方法,添加钩子函数,如图所示
子类茶重写父类方法,实现挂载钩子,如图所示
测试和结果
茶的实现就少了加入柠檬的步骤。这就是钩子函数的作用,他为我们在子类中提供了和更加的灵活性与选择性决定算法的具体实现。
总结:
模板方法模式的实现要素:1.抽象基类 2.具体子类。在抽象基类中要提供一些具体的基本方法,对于各种不同的实现子类而言是相同的,具有共性的。还有一些抽象方法,是对于那些我们只知道具体原则,而不知道实现细节,需要将她延迟到子类实现的一些步骤。还有一些我们可选的钩子函数。最后我们将基本方法,抽象方法和钩子函数按照我们业务逻辑的需求汇总成一个模板方法,这就构成了我们的算法框架,模板方法必须声明成final,不能被子类所复写。
具体子类:1.实现基类中的抽象方法 2.覆盖钩子方法。
模板方法模式的适用场景:
(1)算法或操作遵循相似的逻辑
(2)重构时(把相同的代码提取到父类中)
(3)重要复杂的算法,核心算法设计为模板方法
模板方法模式的优点:1.封装性好 2.复用性好 3.屏蔽细节 4.便于维护
模板方法模式的缺点:继承 java是一个单继承的语言,设想在一个已有的系统当中大量的使用到了继承,这个时候如果我们想要做一些重构,通过模板方法的模式抽取共性,因为我们的类已经出一个继承层次的某个结构之中,再通过模板方法引入新的继承的时候就会遇到困难。