模板类
- 举一个冲泡饮料的例子。泡茶喝泡咖啡除了某些步骤不一样外,大体是一样的,我们可以把冲泡饮料抽象成一个模板,进行共用。而到具体内容的时候,它们再有具体的实现。
- 模板方法:1.烧开水;2.把饮料放到水杯里;3.倒入开水;4.加调味剂。第1、3步都是一样的,只有2、4需要根据需要调整,因此写为抽象方法由子类具体实现。
public abstract class Beverage {
// 具体的模板方法, 要用final关键字进行修饰,避免子类进行修改
public final void prepareBeverageTemplate() {
// 1, 烧开水
boilWater();
// 2, 放到杯中
putIntoCup();
// 加入开水
addHotWater();
// 加入调味应有剂
addCondiments();
}
private void boilWater() {
System.out.println("烧开水");
}
protected abstract void putIntoCup();
private void addHotWater() {
System.out.println("加水");
}
protected abstract void addCondiments();
}
声咖啡子类和茶子类实现这两个方法
public class Coffee extends Beverage { @Override protected void putIntoCup() { System.out.println("把咖啡放到水杯中"); } @Override protected void addCondiments() { System.out.println("加入糖和牛奶"); } } public class Tea extends Beverage { @Override protected void putIntoCup() { System.out.println("把咖啡放到水杯中"); } @Override protected void addCondiments() { System.out.println("加入糖和牛奶"); } }
建立一个test类来测试一下模板模式
public class Test { public static void main(String[] args) { // 咖啡制作 Beverage coffee = new Coffee(); coffee.prepareBeverageTemplate(); // 调用模版 System.out.println("\n***********************\n"); // 茶制作 Beverage tea = new Tea(); tea.prepareBeverageTemplate(); // 调用模版 } }
钩子函数
- 其实第4个步骤不是必须的,因为有些人喝茶或咖啡不喜欢加调料,那么如何让程序更加通用化或者更加体现个性化需求呢?这就需要提供一个钩子函数,具体到每个场景,使用不同的钩子函数。
- 我们把原来的额addCondiments方法放入一个if函数中调用,而if条件就是我们的钩子函数的调用。
prepareBeverageTemplate方法中的代码修改如下:
if(isCustomered){ //加入调味剂 addCondiments(); } //新增isCustomered方法 protected abstract boolean isCustomered(){ return true; }
这时只要在子类中重写这个钩子函数,就实现个性化需求,比如在茶中重写这个方法
public class Tea extends Beverage(){ @Override protected void putIntoCup(){ System.out.println("把茶放入水杯中"); } @Override protected void addCondiments() { System.out.println("加入糖和牛奶"); } @Override protected boolean isCustomered(){ return false; } }
- 运行Test,就可以去掉加调料这个步骤
再举一个例子,下面也是重写了钩子函数的情况
//模板设计模式 subFiles =src.listFiles(new FilenameFilter(){ @Override /** * 重写了文件过滤器,返回为真时才将文件挑选出来,否则将剔除出listFiles * dir 代表src */ public boolean accept(File dir, String name) { //System.out.println(dir.getAbsolutePath()); return new File(dir,name).isFile()&&name.endsWith(".java"); //符合条件 } });