F66永乐集团注册F66永乐集团注册


F66永乐集团娱乐

模版方法模式

目录

情景模板方法使用钩子总结模版方法的应用

情景

泡茶和冲咖啡,代码如下:

public class Coffee { public void prepareRecipe(){ boilWater(); makeCoffee(); pourInCup(); addSugarAndMilk(); } public void boilWater(){ System.out.println("正在烧水"); } public void addSugarAndMilk(){ System.out.println("正在加糖和牛奶"); } public void pourInCup(){ System.out.println("正在将咖啡倒进杯子"); } public void makeCoffee(){ System.out.println("正在用沸水煮咖啡"); }}public class Tea { public void prepareRecipe(){ boilWater(); makeTea(); pourInCup(); addLemon(); } public void boilWater(){ System.out.println("正在烧水"); } public void addLemon(){ System.out.println("正在加柠檬"); } public void pourInCup(){ System.out.println("正在将茶倒进杯子"); } public void makeTea(){ System.out.println("正在用沸水泡茶"); }}

模板方法

上述重复代码,如何复用?重新设计如下:

/** * final 方法不希望子类去覆盖 * 抽象方法延迟到子类中实现 */public abstract class CaffeineBeverage { /* * 模板方法 */ final public void prepareRecipe(){ boilWater(); makeIt(); pourInCup(); addCondiments(); } final public void boilWater(){ System.out.println("正在烧水"); } final public void pourInCup(){ System.out.println("正在将咖啡倒进杯子"); } public abstract void addCondiments(); public abstract void makeIt();}public class Coffee extends CaffeineBeverage{ @Override public void addCondiments() { System.out.println("正在加糖和牛奶"); } @Override public void makeIt() { System.out.println("正在用沸水煮咖啡"); }}public class Tea extends CaffeineBeverage{ @Override public void addCondiments() { System.out.println("正在加柠檬"); } @Override public void makeIt() { System.out.println("正在用沸水泡茶"); }}

public class Test { public static void main(String[] args) { CaffeineBeverage coffee = new Coffee(); coffee.prepareRecipe(); System.out.println("-----"); CaffeineBeverage tea = new Tea(); tea.prepareRecipe(); }}

使用钩子

现在增加一个需求,喝咖啡的顾客可以自主选择是否需要调料。这时就用到了钩子。

代码做一下修改:

public abstract class CaffeineBeverage { final public void prepareRecipe(){ boilWater(); makeIt(); pourInCup(); if(customWantsCondiments()){ addCondiments(); } } final public void boilWater(){ System.out.println("正在烧水"); } final public void pourInCup(){ System.out.println("正在将咖啡倒进杯子"); } public abstract void addCondiments(); public abstract void makeIt(); public boolean customWantsCondiments(){ // 默认认为顾客是想要调料的 return true; }}public class CoffeeWithHook extends CaffeineBeverage{ @Override public boolean customWantsCondiments() { return getUserInput(); } @Override public void addCondiments() { System.out.println("正在加糖和牛奶"); } @Override public void makeIt() { System.out.println("正在用沸水煮咖啡"); } private boolean getUserInput(){ String answer = null; System.out.println("Would you like sugar and milk with your coffee (y/n) ?"); BufferedReader in = new BufferedReader(new InputStreamReader(System.in)); try{ answer = in.readLine(); }catch(Exception e){ System.out.println("IO error to read your answer"); } if(answer.startsWith("y")){ return true; }else{ return false; } }}public class Tea extends CaffeineBeverage{ @Override public void addCondiments() { System.out.println("正在加柠檬"); } @Override public void makeIt() { System.out.println("正在用沸水泡茶"); }}

总结

【定义】已经定义了算法骨架,而将一些步骤延迟到子类中。

【本质】固定算法结构。

【优点】

代码复用性高。容易扩展。基类专注算法架构,子类专注实现,架构清晰。比较灵活,子类可以使用钩子方法对父类算法进行反向约束。

【缺点】

模板类和子类耦合,变更算法骨架需谨慎。

模版方法的应用

Spring 中有太多地方使用了。

工作需要定时从一些网站上抓取数据存储到数据库中,因此创建了一个抽象类 Job,类中定义算法骨架:

    抽取数据。分析数据。存储有用信息。包括处理异常,如果抓取失败,按照既定策略进行重试。

前三个方法是抽象方法,每个子类的实现逻辑千差万别。

欢迎阅读本文章: 叶扬

F66永乐国际永往直前乐在其中

F66永乐集团娱乐