模版方法模式
2015-06-14 20:59
204 查看
一.前言
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(); //在这里控制是否执行addCondiments if (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 response String 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.weight return 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
自动脑补一下,以上。
相关文章推荐
- 用Maven创建第一个web项目
- 如何解决秒杀商品时,商品超卖的情况
- 测试Handler
- Java与微信不得不说的故事——实现微信公众平台与sae服务器的对接
- Codeforces Round #305 (Div. 1)
- Windows各个系列的服务器版本
- win2012 64位系统 iis8支持32位数据库
- [Swust OJ 1126]--神奇的矩阵(BFS,预处理,打表)
- Windows7系统电脑出现蓝屏该怎么处理?
- UI design
- Mysql error 1217
- HDU3605Escape(最大流SAP+状态压缩优化点的个数)
- Cocos2dx基础使用相关面试题
- 谷歌是如何get到设计这个技能的?
- winsows下面firefly服务器搭建
- SQLite数据库增删改查操作
- linux程序设计——内存管理(第七章)
- C++中的临时对象
- 《浪潮之巅》读书笔记3
- vim秒变成source insight,内附安装脚本和资源链接