在我们的日常生活中,模板方法是应用的很广的,我们身边有很多模板方法的身影,举个很高大上的例子就是我们的奥运会的开幕仪式:奥委会对于不同国家举办奥运会开幕式提供的步骤都是一样的:
1.升国旗,奏国歌
2.奥委会人发言
3.文艺汇演
4.奥运运动员入场仪式
5.点燃火炬
但是,对于不同的国家,他们的内容肯定是不一样的,这就是一种模板方法。那么,我们在java的实现中,应该是怎么进行表现呢?
这里再用一个例子来演示,我们的饮料机,一个饮料机可以制作咖啡和茶:
那么我们先定义一个制作饮料的抽象基类:
package com.imooc.pattern.template;
/*
* 抽象基类,为所有子类提供一个算法框架
*
* 饮料
*/
public abstract class RefreshBeverage {
/*
* 制备饮料的模板方法
* 封装了所有子类共同遵循的算法框架
*/
public final void prepareBeverageTemplate(){
//步骤1 将水煮沸
boilWater();
//步骤2 泡制饮料
brew();
//步骤3 将饮料倒入杯中
pourInCup();
if(isCustomerWantsCondiments()){
//步骤4 加入调味料
addCondiments();
}
}
/*
* Hook, 钩子函数,提供一个默认或空的实现
* 具体的子类可以自行决定是否挂钩以及如何挂钩
* 询问用户是否加入调料
*/
protected boolean isCustomerWantsCondiments() {
return true;
}
/*
* 基本方法,将水煮沸
*/
private void boilWater() {
System.out.println("将水煮沸");
}
/*
* 基本方法,将饮料倒入杯中
*/
private void pourInCup() {
System.out.println("将饮料倒入杯中");
}
/*
* 抽象的基本方法,泡制饮料
*/
protected abstract void brew();
/*
* 抽象的基本方法, 加入调味料
*/
protected abstract void addCondiments();
}
是的,制作茶和咖啡的步骤都是一样的,唯一不同的就是炮制和加调味料的实现不一样,所以定义一个模板方法为final,再将其两个不同的方法设置为protected属性,这样方法就只能在它的子类中进行访问和修改了。就能做到不同的饮料不同的制作
所以,制作茶:
package com.imooc.pattern.template;
/*
* 抽象基类,为所有子类提供一个算法框架
*
* 提神饮料
*/
public abstract class RefreshBeverage {
/*
* 制备饮料的模板方法
* 封装了所有子类共同遵循的算法框架
*/
public final void prepareBeverageTemplate(){
//步骤1 将水煮沸
boilWater();
//步骤2 泡制饮料
brew();
//步骤3 将饮料倒入杯中
pourInCup();
if(isCustomerWantsCondiments()){
//步骤4 加入调味料
addCondiments();
}
}
/*
* Hook, 钩子函数,提供一个默认或空的实现
* 具体的子类可以自行决定是否挂钩以及如何挂钩
* 询问用户是否加入调料
*/
protected boolean isCustomerWantsCondiments() {
return true;
}
/*
* 基本方法,将水煮沸
*/
private void boilWater() {
System.out.println("将水煮沸");
}
/*
* 基本方法,将饮料倒入杯中
*/
private void pourInCup() {
System.out.println("将饮料倒入杯中");
}
/*
* 抽象的基本方法,泡制饮料
*/
protected abstract void brew();
/*
* 抽象的基本方法, 加入调味料
*/
protected abstract void addCondiments();
}
制作咖啡:
package com.imooc.pattern.template;
/*
* 具体子类,提供了咖啡制备的具体实现
*/
public class Coffee extends RefreshBeverage {
@Override
protected void brew() {
System.out.println("用沸水冲泡咖啡");
}
@Override
protected void addCondiments() {
System.out.println("加入糖和牛奶");
}
}
测试:
package com.imooc.pattern.template;
public class RefreshBeverageTest {
public static void main(String[] args) {
System.out.println("制备咖啡...");
RefreshBeverage b1 = new Coffee();
b1.prepareBeverageTemplate();
System.out.println("咖啡好了!");
System.out.println("\n******************************************");
System.out.println("制备茶...");
RefreshBeverage b2 = new Tea();
b2.prepareBeverageTemplate();
System.out.println("茶好了!");
}
}
所以,模板方法最重要的就是定义一个抽象基类,模板方法定位finnal,具体子类实现抽象基类的抽象方法,实现个性化的类的操作,钩子方法的设定是让个性化更加详细。