模板方法模式.ppt_第1页
模板方法模式.ppt_第2页
模板方法模式.ppt_第3页
模板方法模式.ppt_第4页
模板方法模式.ppt_第5页
已阅读5页,还剩23页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

1,模板方法模式,模版方法模式是最为常见的几个模式之一,模版方法模式需要开发抽象类和具体子类的设计师之间的协作。一个设计师负责给出一个算法的轮廓和骨架,另一些设计师则负责给出这个算法的各个逻辑步骤。 继承常常作为功能复用的主要工具,这时继承有被滥用的危险。所以,我们有一个设计原则:多用组合,少用继承!,2,第十三章 模板方法模式,是不是继承就根本不该使用呢?事实上对数据的抽象、继承、封装和多态是面向对象语言的最重要的特性。继承不应当被滥用,井不意味着继承根本就不该使用。在GoF书中,绝大多数模式是将依赖于继承的实现转换为基于对象的组合和聚合来实现的。模板方法模式是很少用继承来实现的模式中的一个!而且模版方法模式:鼓励恰当地使用继承。此模式可以用来改写一些拥有相同功能的相关的类,将可复用的一般性的行为代码移到基类里面,而把特殊化的行为代码移到子类里面。熟悉模版方法模式便成为一个重新学习继承的好地方。,3,第十三章 模板方法模式,咖啡因饮料 茶和咖啡都是咖啡因饮料,它们的冲泡方法也很相似: 星巴兹咖啡冲泡法 星巴兹茶冲泡法 把水煮沸 把水煮沸 用沸水冲泡咖啡 用沸水浸泡茶叶 把咖啡倒进杯子 把茶倒进杯子 加糖和牛奶 加柠檬,咖啡和茶的冲泡方法大致上一样。,4,创建咖啡 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“); ,每个方法都实现算法中的一个步骤:煮沸水、冲泡咖啡、把咖啡倒进杯子、加糖和牛奶。,5,创建茶 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“); ,泡茶专有的两个方法。,第二步和第四步与咖啡的实现不同,其它的实现一样。,6,第一版设计,能否改进这个设计?,7,星巴兹咖啡和茶冲泡法分析 星巴兹咖啡和茶的冲泡法采用了相同的算法: 把水煮沸 用热水泡咖啡或茶 把饮料倒进杯子 在饮料内加入适当的调料 第一步和第三步完全相同已经被抽出来,放到基类了。 第二步和第四步的抽象也是相同的。,8,抽象prepareRecipe() 我们遇到的第一个问题就是:茶使用steepTeaBag()和 addLemon()方法,而咖啡使用brewCoffeeGrinds() 和addSugarAndMilk()方法。 咖啡 茶 void prepareRecipe() void prepareRecipe() boilWater(); boilWater(); brewCoffeeGrinds(); steepTeaBag(); pourInCup(); pourInCup(); addSugarAndMilk(); addLemon(); ,9,抽象prepareRecipe()(续) 无论是咖啡的冲泡,还是茶的浸泡,都是用沸水泡,我 们给它一个新的方法名称,比如说brew()。同样,无论是咖啡 加糖和牛奶,还是茶加柠檬,都是加调料,我们也给它一个新 的方法名称addCondiments()。这样,新的prepareRecipe()方法看 起来就象这样: void prepareRecipe() boilWater(); brew(); pourInCup(); addCondiments(); ,10,抽象prepareRecipe()(续) CaffeineBeverage(咖啡因饮料)超类: public abstract class CaffeineBeverage / 抽象类 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“); ,prepareRecipe()声明为final,是不让子类覆盖这个方法!步骤2和步骤4被泛化为brew()和addCondiments()。,这两个方法声明为抽象的,是因为咖啡和茶的做法不同,需要子类实现。,11,抽象prepareRecipe()(续) 咖啡和茶都依赖于超类(咖啡因饮料)处理冲泡法。 public class Coffee extends CaffeineBeverage public void brew() System.out.println(“Dripping Coffee through filter“); public void addCondiments() System.out.println(“Adding Sugar and Milk“); public class Tea extends CaffeineBeverage public void brew() System.out.println(“Steeping the tea“); public void addCondiments() System.out.println(“Adding Lemon“); ,12,我们 做了 什么?,13,会会模板方法 刚刚实现的就是模板方法模式。模板方法定义了一个算法步骤,并允许子类为一个或多个步骤提供实现。 我们再看看咖啡因饮料类的结构(下页)。,14,会会模板方法(续),15,模板方法如何工作(以泡茶为例) 首先需要一个茶对象: Tea = myTea = new Tea(); 然后调用这个模板方法: myTea.prepareRecipe(); 依照这算法制作咖啡因饮料 把水煮沸: boilWater(); / 是在超类中进行的 泡茶,这件事只有子类知道怎么做: brew(); 把茶到进杯子里: pourInCup(); /是在超类中进行的 最后,加进调料。由于调料是各个饮料 独有的,所以由子类来实现它: addCondiments();,模板方法带来的好处?,16,模板方法模式定义,17,模板方法模式类图,18,钩子(hook) 钩子是一种被声明为抽象类的方法,但只有空的或默 认的实现。有了钩子,可以让子类有能力对算法的不同点 进行挂钩。要不要挂钩,由子类自行决定。 abstract class AbstractClass / 细节忽略了 void hook() ,这是一个抽象类中不做任何事情的具体方法,即钩子(hook)。,19,对模板方法挂钩 public abstract class CaffeineBeverageWithHook void prepareRecipe() boilWater(); brew(); pourInCup(); if (customerWantsCondiments() addCondiments(); abstract void brew(); abstract void addCondiments();,20,对模板方法挂钩 void boilWater() System.out.println(“Boiling water“); void pourInCup() System.out.println(“Pouring into cup“); boolean customerWantsCondiments() return true; ,这就是一个钩子,子类可以覆盖这个方法,但不一定这么做。,21,使用钩子 为了使用钩子,我们在子类中覆盖它。在这里,钩子控 制咖啡因饮料是否执行某部分算法。或更确切地说是在饮料 中要不要加进调料。 public class CoffeeWithHook extends CaffeineBeverageWithHook public void brew() System.out.println(“Dripping Coffee through filter“); public void addCondiments() System.out.println(“Adding Sugar and Milk“); ,22,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; ,覆盖了钩子。让用户输入对调料的决定。,通过命令行获得用户的输入。,23,执行测试程序 public class BeverageTestDrive public static void main(String args) TeaWithHook teaHook = new TeaWithHook(); CoffeeWithHook coffeeHook = new CoffeeWithHook(); System.out.println(“nMaking tea.“); teaHook.prepareRecipe(); System.out.println(“nMaking coffee.“); coffeeHook.prepareRecipe(); ,24,测试结果,加柠檬。,不加糖和牛奶。,25,好莱坞原则,好莱坞原则可以防止“依赖腐败”。当高层组件依赖 低层组件,低层组件又依赖高层组件,高层组件又依赖 边侧组件,边侧组件又依赖高层组件,依赖腐败就发 生了。在这种情况下,没有人可以轻易搞懂系统是如何 设计的。,26,好莱坞原则(续),在好莱坞原则下,允许低层组件挂钩到系统上,但是 高层组件会决定什么时候和怎样使用这些低层组件。即高 层组件对低层组件的方式是“别调用我们,我们

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论