1、模板方法模式概要
定义: 在一个方法中定义一个算法的骨架,而将一些步骤延迟到子类中。模版方法使得子类可以在不改变算法结构的情况下,重新定义算法中某些步骤。
模板模式和策略模式很相像但却不相同
模板模式解决的是算法模式内部的问题,而策略模式解决的是扩展问题,本质上是不一样的
另外我们应该遵守好莱坞原则:让我们来找你,而不是你找我们
2、模板方法模式举例
首先我们想象一下冲咖啡和泡茶的过程
冲咖啡
- 烧水
- 沸水冲咖啡
- 把咖啡倒进被子
- 加一点糖或者牛奶
泡茶
- 烧水
- 沸水冲茶叶
- 把茶倒进杯子里
- 加柠檬
我们很容易发现他们的流程是一样的,而且他们的有些操作也是相同的,比如说1,他们都需要烧水
如果我们写两个类的话就会存在重复的方法,我们如何能够减少代码的重复呢?
我们可以定义一个抽象父类
public abstract class Beverage {
final void prepare(){
boilWater();
brew();
pourInCup();
addCondiments();
}
abstract void brew();
abstract void addCondiments();
void boilWater(){
System.out.println("Boiling water");
}
void pourInCup(){
System.out.println("Pouring into cup");
}
}
在这个抽象父类中
①我们把整体流程定义出来,以final命名,防止子类覆盖
②我们把公共的方法在父类中编写,需要动态改变的类以abstract命名
在子类中,只需要把动态的方法重写即可,但是你可能会产生疑问?这个模板就这样写死了吗?我们不能动态的改变模板吗?
答案是:当然可以,我们只需要做出一点微小的改变,比如加入Hook
public abstract class Beverage {
final void prepare(){
boilWater();
brew();
pourInCup();
if (hook()){
addCondiments();
}
}
abstract void brew();
abstract void addCondiments();
void boilWater(){
System.out.println("Boiling water");
}
void pourInCup(){
System.out.println("Pouring into cup");
}
boolean hook(){
return true;
}
}
我们加入一个钩子方法,用来判断某一方法是否需要执行。如果不需要执行只需要在子类中覆盖方法并且赋值为flase即可
public class Coffee extends Beverage {
private boolean isCondiments;
public boolean isCondiments() {
return isCondiments;
}
public void setCondiments(boolean condiments) {
isCondiments = condiments;
}
@Override
void brew() {
System.out.println("沸水冲咖啡");
}
@Override
void addCondiments() {
System.out.println("加一点糖或者牛奶");
}
@Override
boolean hook() {
return isCondiments;
}
}
在子类中这样改写,我们来看看测试结果如何
public static void main(String[] args) {
Coffee coffee = new Coffee();
coffee.prepare();
}
控制台显示
如果我们把isCondiments的值设置为true呢
public static void main(String[] args) {
Coffee coffee = new Coffee();
coffee.setCondiments(true);
coffee.prepare();
}
这样我们所想要的动态变化模板的结果就出现了
3、总结
总的来说,模板方法模式是一种很常见很简单的设计模式,非常通俗易懂,它能够减少重复代码的使用。它任然遵守着好莱坞原则
好莱坞原则:别调用(打电话给)我们,我们会调用(打电话给)你。(即高层组件对低层组件的方式是:别调用我们,我们会调用你们)。
子类只是修改父类的细节,整体还是又父类主导,由模板主导
它能够保证代码的同一和复用