模板方法模式
eg:
要写一段程序实现泡茶和泡咖啡,方法如下:
泡茶的方法:
1.把水煮沸
2.用沸水浸泡茶叶
3.把茶倒进杯子
4.加柠檬
泡咖啡的方法:
1.把水煮沸
2.用沸水冲泡咖啡
3.把咖啡倒进杯子
4.加糖和牛奶
通过观察,我们可以发现这两种饮料的冲泡都采用了相同的算法:
1.把水煮沸
2.用热水泡咖啡或茶
3.把饮料倒进杯子里
4.在饮料内加入适当的调料
所以我们很自然的就会想到通过将公共的地方抽取出来,放在父类,子类继承父类,在方法中实现各自的操作,就像这样:
public abstract class CaffeineBeverage{
void final prepareRecipe(){//模板方法,用作一个算法的模板,在这个模板中,算法内的每一个步骤都被一个方法代表了
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");
}
}
模板方法定义了一个算法步骤,并允许子类为一个或多个步骤提供实现
现在,当我们要冲泡咖啡或茶就很简单了,只要让子类Tea和Coffee继承CaffeineBeverage然后实现各自特有的步骤:
public class Tea extends CaffeineBeverage{
public void brew(){
System.out.println("Steeping the tea");
}
public void addCondiments(){
System.out.println("Adding Lemon");
}
}
public class Coffee extends CaffeineBeverage{
public void brew(){
System.out.println("Dripping Coffee through filter");
}
public void addCondiments(){
System.out.println("Adding Sugar and Milk");
}
}
然后我们再直接调用子类的模板方法就可以了:
Tea myTea = new Tea();
myTea.prepareRecipe();
以上的实现就是模板方法模式,现在我们再来看下定义:
模板方法:
- 是一个方法
- 用作一个算法的模板
- 算法内的每一个步骤都被一个方法代表
- 某些方法是由父类处理的,某些方法是由子类处理的(声明为抽象)
定义
模板方法模式在一个方法中定义了一个算法的骨架,而将一些步骤延迟到子类中。模板方法使得子类可以在不改变算法结构的情况下,重新定义算法中的某些步骤
除了上述外,模板方法中可能还有“hook”(钩子)方法,这是一个默认不做事的方法,即在父类中有空实现或默认的实现,钩子的存在可以让子类有能力对算法的不同点进行挂钩,子类可以根据情况决定要不要覆盖它们如:
public abstract class CaffeineBeverage{
void final prepareRecipe(){
boilWater();
brew();
pourInCup();
if(customerWantsCondiments){//顾客想要加饮料才执行addCondiments()方法
addCondiments();
}
}
abstract void brew();
abstract void addCondiments();
void boilWater(){
//实现
System.out.println("Boiling water");
}
void pourInCup(){
//实现
System.out.println("Pouring into cup");
}
boolean customerWantsCondiments(){//默认返回true,子类可以覆盖此方法(顾客不想加饮料时)
return true;
}
}
上述操作可以通过钩子作为条件控制,影响抽象类中的算法流程
钩子的作用:
1.让子类实现算法中可选的部分,或者在钩子对于子类的实现并不重要的时候,子类可以此钩子置之不理
2.让子类能够有机会对模板方法中某些即将发生的(或刚刚发生的)步骤作出反应
模板方法与策略模式比较
策略模式:
1.定义了一个算法家族,并让这些算法可以互换,正因为每一个算法都被封装起来了,所以客户可以轻易地使用不同的算法
2.通过对象组合的方式,让客户选择算法实现
3.使用对象组合,更有弹性,客户可以在运行时改变算法,主要改用不同的策略对象
4.不依赖任何人,整个算法都是自己搞定
模板方法
1.定义了一个算法的大纲,由子类定义其中某些步骤的内容,个别步骤可以有不同的实现细节,但是算法的结构依然维持不变
2.用继承进行算法的实现
3.对算法有更多的控制权,不会重复代码
4.依赖超类中的方法的实现