模板方法模式
泡咖啡和泡茶,二者相似的动作,可以抽象成一个模板
模板方法模式,在我看来,就像是一个可以自定义实现部分方法的外观模式。
代码模板
一般模板方法的呈现方式,如下:
public abstract class TempMethodClass {
final void templateMethod() {
method1();
abstractMethod1();
method2();
abstractMethod2();
}
void method1() {
//具体实现
}
void method2() {
//具体实现
}
abstract void abstractMethod1();
abstract void abstractMethod2();
}
模板方法一般设置为final
,这是为了防止子类覆写这个方法。
代码实例
泡茶,泡咖啡,都有下面这四个步骤:
- 烧水
- 加入主料(茶叶、咖啡粉)
- 倒入开水
- 加入额外佐料(奶油,糖)
其中,烧水和倒水的方法,是一模一样的,但是,加主料和佐料的方法不一样。
这是模板类,其中有一个模板方法Drink
:
public abstract class Drink {
/**
* 使用final申明,是因为不希望子类覆写这个方法
*/
final void prepare() {
hotWater();
addMeta();
pour();
addExtra();
}
/**
* pour和hotwater方法,因为是所有类通用的
* 不需要更改,所以可以直接实现
*/
void pour() {
System.out.println("正在倒水");
}
void hotWater() {
System.out.println("正在烧水");
}
/**
* 添加原料和添加额外物品
* 因为对于不同饮料,可能需求不一样
* 所以这里用抽象类,让子类自己来实现
*/
abstract void addMeta();
abstract void addExtra();
}
茶类:
public class Tea extends Drink{
@Override
void addMeta() {
System.out.println("正在加入茶叶");
}
@Override
void addExtra() {
System.out.println("正在加入红茶佐料");
}
}
咖啡类:
public class Coffee extends Drink{
@Override
void addMeta() {
System.out.println("正在加入咖啡粉");
}
@Override
void addExtra() {
System.out.println("正在加入白砂糖");
}
}
钩子函数
钩子函数,一般实现是空的,或者返回一个默认值
钩子函数的示例:
public abstract class TempMethodClass {
final void templateMethod() {
method1();
abstractMethod1();
method2();
abstractMethod2();
}
void method1() {
//具体实现
}
void method2() {
//具体实现
}
abstract void abstractMethod1();
abstract void abstractMethod2();
/**
* 钩子函数,啥都不实现
* 或者返回一个返回值
* @return
*/
boolean hook() {
return true;
}
}
一般用法是这个样子的:
父类中,添加一个钩子函数
public abstract class Drink {
final void prepare() {
hotWater();
addMeta();
pour();
/**
* 钩子函数
* 如果子类什么都不管,就接着执行
* 如果子类覆写这个方法,那就可能导致结果变化
*/
if (needExtra()) {
addExtra();
}
}
void pour() {
System.out.println("正在倒水");
}
void hotWater() {
System.out.println("正在烧水");
}
abstract void addMeta();
abstract void addExtra();
/**
* 钩子函数
* @return
*/
boolean needExtra() {
return true;
}
}
Coffee
类,覆写这个钩子函数:
更具输入,判断用户是否想添加额外作料
public class Coffee extends Drink{
@Override
void addMeta() {
System.out.println("正在加入咖啡粉");
}
@Override
void addExtra() {
System.out.println("正在加入白砂糖");
}
/**
* 覆写钩子函数
* 如果用户输入yes,则继续添加作料
* 否则不添加
* @return
*/
@Override
boolean needExtra() {
String answer = getInput();
if ("yes".equals(answer)) return true;
return false;
}
public String getInput() {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
String answer="";
try {
answer = br.readLine();
} catch (IOException e) {
e.printStackTrace();
}
return answer;
}
}
测试:
模板方法的变体
Java API中,模板方法不会这么一板一眼的出现
比如compareTo()
方法
具体的不展开了