什么是模板方法模式
模板方法模式(Template Method Pattern)在一个方法中定义一个算法的骨架,而将一些步骤延迟到子类中。模板方法使得子类可以在不改变算法接口的情况下,重新定义算法的某些步骤。
理解模板方法模式
这个模式是用来创建一个算法的模板的。什么是模板呢?其实模板就是一个方法,只不过这个方法可以有很多不同的实现方法而已。更具体地说,这个方法将算法定义成一系列步骤,其中的任何步骤都可以是抽象的,被子类根据实际情况具体实现。这样呢,即可以保证算法的整体结构不变,又可以让子类重新定义自己的算法。
模板方法模式类图
下面分别来说说各部分的作用:
AbstractClass
就是一个抽象方法,它定义了一些抽象的方法比如primitiveOperation1()
和primitiveOperation2()
,同时也定义了一个模板方法templateMethod()
。模板方法在实现的过程当中使用到了这两个抽象方法,但是模板方法和它们的具体实现解耦了。
ConcreteClass
是一个具体的方法,是上面的AbstractClass
抽象类的子类,可能不止一个子类。这个类实现具体的操作,当模板方法需要这两个方法的时候就会调用它们。
实例分析-茶饮之道
我们知道现在的奶茶的品类非常的多,有绿茶,红茶,珍珠奶茶,红豆奶茶,还有卡布奇诺等等。这些奶茶是如何被做出来的呢,工具都一样,流程也一样,但是做出来的产品却不同,秘密是什么?其实这里面就藏着我们今天的主角-模板方法模式。
先来分析一下做奶茶需要哪几步?
可以看到这份培训手册中明确说明了咖啡和茶的生产工艺,都是有四个步骤,
- 烧,将水烧开
- 熬,在开水中把茶或者咖啡熬好
- 倒,把茶或者咖啡倒进杯子
- 添,添加一些调味剂
我们可以看到这几步就构成了大多数奶茶的生产流程。但是我们是不是应该将这些步骤封装一下呢?后面有什么新的产品上线就可以让店员快速学习上手。
下面我们看看如何抽象出这个产品:
定义茶品制作方法:
1 | package com.qinjiangbo.template.methods; |
茶的制造工艺:
1 | package com.qinjiangbo.template.methods; |
咖啡的制造工艺:
1 | package com.qinjiangbo.template.methods; |
后面其实我们可以依据这个模板写出很多奶茶的制作工艺的,扩展起来非常方便。
实例测试
写了一个测试用例,比较简单:
1 | package com.qinjiangbo.template.test; |
输出的结果如下:
1 | Boiling water... |
结果是符合预期的。
模板方法模式 vs 策略模式
其实大伙儿对模板方法模式和策略模式一直都很容易搞混,因为它们都是来改变一些方法或者策略来实现不同的目的。这里主要主要谈谈它们的不同吧。
- [目的]模板方法模式的目的是定义一系列方法的一个轮廓,允许子类选择去实现其中的具体步骤;而策略模式的目的是能够定义一系列可以相互替换的算法。
- [侧重点]模板方法模式更加侧重的是一条算法线上的方法点的多样性,线上的可以被替换的点是一定能够被执行的,只不过每一个点的行为可能不一样而已;但是策略模式更加侧重的是整条算法线的替换,它的各种算发现每次只能执行一条。
- [方法可见性]模板方法模式中除了模板方法是公开的以外,其他的具体执行的方法点都是对外访问限制的;而策略模式中通常各个方法点都是可以访问到的。
- [继承组合]模板方法模式基于的是类的继承思想,子类决定父类的某个抽象方法的具体实现;而策略模式基于的是对象的组合,将不同算法的对象组合起来从而实现算法的相互替换。
总结
模板方法模式为我们提供了一组能够替换掉具体方法点的操作思想。其实这种思想在Java的JDK中也有具体的体现,比如Arrays.sort()
方法,这个方法里面其实使用的就是模板方法模式,模板方法就是sort()
。我们可以利用模板方法提供更为灵活的编码风格。上面最后一点说的[继承组合]不同点其实会有人提出疑问,不是说要多用组合,少用继承嘛?为啥现在还要用?这个问题应该这么来考虑,设计模式的初衷是找到最符合某一类问题的解决方法和模式,这个需要依据具体的情况具体分析,大多数情况下我们还是坚持多用组合,少用继承的思想。