模版方法模式

来源:互联网 发布:大数据金融论坛 编辑:程序博客网 时间:2024/06/05 04:20

一.前言

what is templatemethod,一句话我的理解:
在超类并定义了算法的步骤,定义了共有步骤的具体实现,并允许子类为一个或者多个步骤提供实现。
解释:比如在超类中定义算法步骤包括5步,其中1、3、5是在超类中实现的,2、4的实现在子类中有不同,所以子类各自实现。



二.简单的例子

泡茶和冲咖啡,他们的步骤分别是:
泡茶:
1.把水煮沸
2.用沸水浸泡茶叶
3.把茶水倒进杯子
4.加柠檬
冲咖啡:
1.把水煮沸
2.用沸水冲泡咖啡
3.把咖啡倒进杯子

4.加糖和牛奶


对应的代码如下:

public class Tea { void prepareRecipe() {boilWater();steepTeaBag();pourInCup();addLemon();} public void boilWater() {System.out.println("Boiling water");} public void steepTeaBag() {System.out.println("Steeping the tea");} public void addLemon() {System.out.println("Adding Lemon");} public void pourInCup() {System.out.println("Pouring into cup");}}public class Coffee { void prepareRecipe() {boilWater();brewCoffeeGrinds();pourInCup();addSugarAndMilk();} public void boilWater() {System.out.println("Boiling water");} public void brewCoffeeGrinds() {System.out.println("Dripping Coffee through filter");} public void pourInCup() {System.out.println("Pouring into cup");} public void addSugarAndMilk() {System.out.println("Adding Sugar and Milk");}}

很明显,这两个类是存在了重复代码的,既然他们步骤是类似的,应该将共同的部分抽取出来,放入一个基类中。我们不难得出下面的关系:



饮料超类:

public abstract class Beverage {  final void prepareRecipe() {boilWater();brew();pourInCup();addCondiments();} abstract void brew();  abstract void addCondiments(); void boilWater() {System.out.println("Boiling water");}  void pourInCup() {System.out.println("Pouring into cup");}}

茶:

public class Tea extends Beverage {public void brew() {System.out.println("Steeping the tea");}public void addCondiments() {System.out.println("Adding Lemon");}}

咖啡:

public class Coffee extends Beverage {public void brew() {System.out.println("Dripping Coffee through filter");}public void addCondiments() {System.out.println("Adding Sugar and Milk");}}

想到有个问题,像我们家妹纸,喝东西都喜欢原味的,我这强制加了Condiment好像不好诶,肿么办,为了我们家妹纸,当然不能提供这么愚蠢的设计,有办法的,我们使用钩子,改造上述代码改造如下:

public abstract class BeverageWithHook { void prepareRecipe() {boilWater();brew();pourInCup();//在这里控制是否执行addCondimentsif (customerWantsCondiments()) {addCondiments();}} abstract void brew(); abstract void addCondiments(); void boilWater() {System.out.println("Boiling water");} void pourInCup() {System.out.println("Pouring into cup");}//默认为都需要加调味料boolean customerWantsCondiments() {return true;}}//拥有钩子的茶public class TeaWithHook extends BeverageWithHook { public void brew() {System.out.println("Steeping the tea");} public void addCondiments() {System.out.println("Adding Lemon");} public boolean customerWantsCondiments() {String answer = getUserInput();if (answer.toLowerCase().startsWith("y")) {return true;} else {return false;}}//在代码中添加供用户输入的部分,模拟用户的选择private String getUserInput() {// get the user's responseString answer = null;System.out.print("Would you like lemon with your tea (y/n)? ");BufferedReader in = new BufferedReader(new InputStreamReader(System.in));try {answer = in.readLine();} catch (IOException ioe) {System.err.println("IO error trying to read your answer");}if (answer == null) {return "no";}return answer;}}//类似的,拥有钩子的咖啡public class CoffeeWithHook extends BeverageWithHook { public void brew() {System.out.println("Dripping Coffee through filter");} public void addCondiments() {System.out.println("Adding Sugar and Milk");} public boolean customerWantsCondiments() {String answer = getUserInput();if (answer.toLowerCase().startsWith("y")) {return true;} else {return false;}} private String getUserInput() {String answer = null;System.out.print("Would you like milk and sugar with your coffee (y/n)? ");BufferedReader in = new BufferedReader(new InputStreamReader(System.in));try {answer = in.readLine();} catch (IOException ioe) {System.err.println("IO error trying to read your answer");}if (answer == null) {return "no";}return answer;}}

上述的钩子控制了是否向饮料中加入调味料。总结一下上面的思路:
当子类必须提供算法中某个方法或者步骤的实现时,就使用抽象方法。如果这个算法是可选的,就使用钩子,子类也可以覆盖钩子,但不强制这么做。


一个好玩的原则,好莱坞原则:

别打电话给我,我会打电话给你。
翻译一下就是:
别调用我们,我们会调用你。
在模版方法中,就是基类调用了子类的方法。


三.排序方法对于模版方法的运用

java的数组类提供了一个模版的排序方法sort,源码如下:

public static void sort(Object[] a){Object aux[] = (Object [])a.clone();mergeSort(aux,a,0,a.length,0);}private static void mergeSort(Object src[],Object dest[],int low,int high,int off){for(int i=low;i<high;int off){for(int j=i;j>low&&((Comparable) dest[j-1]).compareTo((Comparable) dest[j])>0;j--){swap(dest,j,j-1);}}}

从上面都代码可以看出,会调用数组中元素的compareTo方法,这个方法就需要在元素子类中实现这个方法,例如排序一个鸭子类:

public class Duck implements Comparable {String name;int weight;  public Duck(String name, int weight) {this.name = name;this.weight = weight;} public String toString() {return name + " weighs " + weight;}    public int compareTo(Object object) { Duck otherDuck = (Duck)object;  if (this.weight < otherDuck.weight) {return -1;} else if (this.weight == otherDuck.weight) {return 0;} else { // this.weight > otherDuck.weightreturn 1;}}}

测试函数如下:

public class DuckSortTestDrive {public static void main(String[] args) {Duck[] ducks = { new Duck("Daffy", 8), new Duck("Dewey", 2),new Duck("Howard", 7),new Duck("Louie", 2),new Duck("Donald", 10), new Duck("Huey", 2) };System.out.println("Before sorting:");display(ducks);Arrays.sort(ducks); System.out.println("\nAfter sorting:");display(ducks);}public static void display(Duck[] ducks) {for (int i = 0; i < ducks.length; i++) {System.out.println(ducks[i]);}}}

这个跟模版方法虽然不能完全重合,但是基本思想是符合的:
1.鸭子数组
2.调用Array.sort
3.实现数组中鸭子的compareTo



自动脑补一下,以上。


0 0
原创粉丝点击