模板方法模式

一、引入一个例子:做茶和咖啡步骤很多都是重复的


换句话说就是基本算法步骤是一样的,只不过在某些地方可能有一些改变比如

如果用传统方法可能就是说不同的算法实现一个不同的类,但再来一个冲燕麦,可能1/4还是一样的,所以我们想到要把相同的提出来而把不同的封装出去,可能使用的就是引入2/3两个类然后再执行方法,但是问题又来了可不可以不这么麻烦,就是一个方法嘛,还需要弄个类。

二、我们看一下下面的方式:

定义冲饮料的超类:

那么对于冲茶只需要重写抽象方法就可以了:

泡茶过程:


这个方法优点就是我们的算法流程是没有变化的,prepareRecipe方法用final修饰表示不能变化。需要修改的代码只需要重写就可以了。

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

注意:
1、这个和之前说的多用组合少用继承好像有冲突,其实不是,正所谓具体问题具体分析,之前说的继承是因为可能会出现大量的重复代码,而这个里面之所以有些方法单独写,就是不会出现重合,或者说留这么一个方法是让使用者对于不同的应用不同的方法而言的。其实我认为用组合的方式也不是不可以。
2、模板方法其实更多的体现在给出一个模板来,然后让使用者针对这个模板中的某些具体步骤给出实现,这个需要场景应用了。

四、如果说模板方法中某个步骤我们可能需要针对特殊情况更改,但是大多数情况是一样的,那么这时候可以使用挂钩。

一个例子:饮料中是否加入调料。

针对于是否加入调料我们覆盖该方法:

执行代码:

使用了钩子尽然可以改变算法流程,非常酷!

五 设计原则:好莱坞原则:别调用(打电话给)我们,我们会调用(打电话给)你。

就像模板方法模式,高层组件就是咖啡因饮料,虽然里面有些方法让子类继承了,但是子类执行的时候不是来调用高层,而是通过高层调用低层的。
还有工厂模式和观察这模式都是按照这个原则的。


#六、具体应用

1、JDK应用:排序

Arrays类中有一个静态方法是
public static void sort(Object[] a)


根据元素的自然顺序对指定对象数组按升序进行排序。数组中的所有元素都必须实现 Comparable 接口。此外,数组中的所有元素都必须是可相互比较的(也就是说,对于数组中的任何 e1 和 e2 元素而言,e1.compareTo(e2) 不得抛出 ClassCastException)。


  • 解释一下就是说修饰a的对象必须是实现了Comparable接口的,而该接口只有一个方法就是int comparable,小于、等于或大于指定对象,则分别返回负整数、零或正整数.
  • 所以该sort就是对那些非数字型的排序的一种方法。

具体实现(源码):


上面就是这个算法的具体流程,但是关于中间如何比较两个对象的大小是未知的,所以这个部分留给了具体的对象去实现了,之前使用子类继承超类的方式,因为我们要继承这个算法流程,现在是使用静态方法,是因为你要保证所有数组都可以,然后如果对象实现了比较的接口,就可以直接调用该方法了。
鸭子的实现:

让我们测试一下这个程序:

2、钩子的应用:Applet



1、模板方法定义的是方法的步骤,这些步骤会延迟到子类
2、模板方法抽象类可以定义具体方法,抽象方法和钩子
3、为了防止子类改变模板方法中的算法,可以将模板方法申明为final
4、好莱坞规则告诉我们将抉择权放在高层组件上,来决定如何以及何时调用底层模块
5、策略模式和模板方法都是封装算法,一个是组合一个是继承
6、工厂方法是模板方法的一种特殊版本。





原文地址:https://www.cnblogs.com/oneNightStand/p/6f93d3be75b3dff8ccf9aab952cb3c9a.html