模板方法模式(Template Method Pattern)
模板方法模式定义:在一个方法中定义一个算法的骨架,而将一些步骤延迟到子类中。模板方法使得子类可以在不改变算法结构的条件下,重新定义算法中的某些步骤
例如:准备一杯咖啡与准备一杯柠檬茶有很多相同步骤:
准备咖啡:烧水- 冲泡咖啡 - 倒入杯中 - 加糖
准备柠檬茶:烧水- 冲泡茶 - 倒入杯中 - 加柠檬
public class Coffee { public void boilWater(){}; public void makeCoffee(){}; public void pourInCup(){}; public void addSugar(){}; public void prepareCoffee(){ boilWater(); makeCoffee(); pourInCup(); addSugar(); }; }
通常的做法是抽象出一个共同的父类,将相同的步骤移至父类中:
public class Beverage { public void boilWater(){}; public void pourInCup(){}; }
public class Coffee extends Beverage{ public void makeCoffee(){}; public void addSugar(){}; public void prepareCoffee(){ boilWater(); makeCoffee(); pourInCup(); addSugar(); }; }
简洁多了,但是仔细观察,冲泡咖啡与冲泡茶可以抽象为冲泡方法,加糖与加柠檬可以抽象为加配料方法:
public abstract class Beverage { public void boilWater(){}; public abstract void make(); public void pourInCup(){}; public abstract void add(); }
public class Coffee extends Beverage{ public void make(){ System.out.println("make coffee"); }; public void add(){ System.out.println("add sugar"); }; public void prepareCoffee(){ boilWater(); this.make(); pourInCup(); this.add(); }; }
此时已经可以清楚的发现,prepareCoffee与prepareTea的步骤已经完全一样了,可抽象至共同父类Beverage中
public abstract class Beverage { public void boilWater(){}; public abstract void make(); public void pourInCup(){}; public abstract void add(); public void prepare(){ boilWater(); make(); pourInCup(); add(); }; }
public class Coffee extends Beverage{ public void make(){ System.out.println("make coffee"); }; public void add(){ System.out.println("add sugar"); }; }
如果想要实现特定的准备咖啡流程,只需在Coffee类中重写Beverage的prepare方法即可
如果想要Beverage类所有子类的准备流程(必须严格按照烧水 - 冲泡 - 倒入杯中 - 加配料这一流程)完全一致,且不允许修改,只需把Beverage类的prepare方法修改为final类型即可
public abstract class Beverage { public void boilWater(){}; public abstract void make(); public void pourInCup(){}; public abstract void add(); public final void prepare(){ boilWater(); make(); pourInCup(); add(); }; }
为所有的子类提供统一的固定的准备流程,这就是模板方法模式,这里面固定的流程即为模板方法模式定义中的算法骨架
子类可以在不改变算法流程的条件下,重新定义算法中的某些步骤,如:make方法和add方法由子类决定如何实现
上面的设计对流程的控制太过严苛,很难在实际应用中使用,当然通过一些改动,使子类除了能够决定特定步骤的具体实现方式之外,还可以对流程进行控制:
public abstract class Beverage { public void boilWater(){}; public abstract void make(); public void pourInCup(){}; public abstract void add(); public final void prepare(){ boilWater(); make(); pourInCup(); if(addOrNot()){ add(); } }; protected boolean addOrNot(){ return true; } }
public class Coffee extends Beverage{ public void make(){ System.out.println("make coffee"); }; public void add(){ System.out.println("add sugar"); }; protected boolean addOrNot(){ try { System.out.println("Have some sugar?Y/N"); BufferedReader reader = new BufferedReader(new InputStreamReader(System.in)); String in = reader.readLine(); if(null == in || in.equals("") || in.equals("N")){ return false; } return true; } catch (IOException e) { e.printStackTrace(); return false; } } }测试一下:
public class Test { public static void main(String[] args) { Beverage b = new Coffee(); b.prepare(); } }
make coffee Have some sugar?Y/N Y add sugar
make coffee Have some sugar?Y/N N