经验首页 前端设计 程序设计 Java相关 移动开发 数据库/运维 软件/图像 大数据/云计算 其他经验
当前位置:技术经验 » Java相关 » 设计模式 » 查看文章
设计模式之模板方法模式(二)
来源:cnblogs  作者:小酒窝  时间:2019/6/3 9:01:18  对本文有异议

上一篇我们已经学会了模板方法模式,这次我们继续来深入学习下。毕竟学会只是第一步,还有更进一步的学习和深入等着我们呢。

我们先来看下,对模板方法模式的一个总结的类图:

让我们细看抽象类是如何被定义的,包含了它内含的模板方法和原语操作。

  1. abstract class AbstractClass {
  2. // 这就是模板方法。它被声明为final,以免子类改变这个算法的顺序
  3. final void templateMethod() {
  4. // 模板方法定义了一连串的步骤,每个步骤由一个方法代表
  5. primitiveOperation1();
  6. primitiveOperation2();
  7. concreteOperation();
  8. hook();
  9. }
  10. abstract void primitiveOperation1();
  11. abstract void primitiveOperation2();
  12. final void concreteOperation() {
  13. // 这里是实现
  14. }
  15. // 这是一个具体的方法,但他什么都不做。我们叫它为hook(钩子),马上就来揭晓它如何使用
  16. void hook();
  17. }

对模板方法进行挂钩

钩子是一种被声明在抽象类中的方法,但只有空的或者默认的实现。钩子的存在,可以让子类有能力对算法的不同点进行挂钩。要不要挂钩,由子类决定。

钩子有很多用途,我们先看其中一个:

  1. public abstract class CaffeineBeverageWithHook {
  2. final void prepareRecipe() {
  3. boilWater();
  4. brew();
  5. pourInCup();
  6. // 我们加上一个小小的条件语句,该条件是否成立,是由一个具体方法决定
  7. if (customerWantsCondiments()) {
  8. addCondiments();
  9. }
  10. }
  11. abstract void brew();
  12. abstract void addCondiments();
  13. void boilWater() {
  14. System.out.println("Boiling water");
  15. }
  16. void pourInCup() {
  17. System.out.println("Pouring into cup");
  18. }
  19. // 这就是一个钩子,子类可以覆盖这个方法,但不一定需要使用
  20. boolean customerWantsCondiments() {
  21. return true;
  22. }
  23. }

为了使用钩子,我们在子类中覆盖它。在这里,钩子控制了咖啡因饮料是否执行某部分算法;比如,饮料中是否需要加进调料

  1. public class CoffeeWithHook extends CaffeineBeverageWithHook {
  2. public void brew() {
  3. System.out.println("Dripping Coffee through filter");
  4. }
  5. public void addCondiments() {
  6. System.out.println("Adding Sugar and Milk");
  7. }
  8. public boolean customerWantsCondiments() {
  9. // 询问用户,是否要加调料
  10. String answer = getUserInput();
  11. if (answer.toLowerCase().startsWith("y")) {
  12. return true;
  13. } else {
  14. return false;
  15. }
  16. }
  17. private String getUserInput() {
  18. String answer = null;
  19. System.out.print("Would you like milk and sugar with your coffee (y/n)? ");
  20. BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
  21. try {
  22. answer = in.readLine();
  23. } catch (IOException ioe) {
  24. System.err.println("IO error trying to read your answer");
  25. }
  26. if (answer == null) {
  27. return "no";
  28. }
  29. return answer;
  30. }
  31. }

上面就是一个钩子,询问顾客是否想要调料?如果需要,就执行内容,否则就不执行。测试代码如下:

  1. public class BeverageTestDrive {
  2. public static void main(String[] args) {
  3. Tea tea = new Tea();
  4. Coffee coffee = new Coffee();
  5. System.out.println("\nMaking tea...");
  6. tea.prepareRecipe();
  7. System.out.println("\nMaking coffee...");
  8. coffee.prepareRecipe();
  9. TeaWithHook teaHook = new TeaWithHook();
  10. CoffeeWithHook coffeeHook = new CoffeeWithHook();
  11. System.out.println("\nMaking tea...");
  12. teaHook.prepareRecipe();
  13. System.out.println("\nMaking coffee...");
  14. coffeeHook.prepareRecipe();
  15. }
  16. }

执行结果如下:茶要加调料就给你加上了;咖啡不需要加调料,就没给你加

  1. Making tea...
  2. Boiling water
  3. Steeping the tea
  4. Pouring into cup
  5. Would you like lemon with your tea (y/n)? y
  6. Adding Lemon
  7. Making coffee...
  8. Boiling water
  9. Dripping Coffee through filter
  10. Pouring into cup
  11. Would you like milk and sugar with your coffee (y/n)? n

那么,我们使用钩子的真正目的是什么呢?

钩子有几种用法。如我们之前所说的,钩子可以让子类实现算法中可选的部分,或者在钩子对于子类的实现并不重要的时候,子类可以对此钩子置之不理。钩子的另一个用法,是让子类能够 有机会对模板方法中某些即将发生的(或刚刚发生的)步骤做出反应。比方说,名为justReOrderedList()的钩子方法允许子类在内部列表重新组织后执行某些动作(例如在屏幕上重新显示数据)。正如你刚刚看到的,钩子也可以让子类有能力为其抽象类做一些决定。

好莱坞原则

好莱坞原则:别调用(打电话给)我们,我们会调用(打电话给)你。

好莱坞原则可以给我们一种防止“依赖腐败”的方法。当高层组件依赖低层组件,而低层组件又依赖高层组件,而高层组件又依赖边侧组件,而边侧组件又依赖低层组件时,依赖腐败就发生了。在这种情况下,没有人可以轻易地搞懂系统是如何设计的。

在好莱坞原则下,我们允许低层组件将自己挂钩到系统上,但是高层组件会决定什么时候和怎样使用这些低层组件。换句话说,高层组件对待低层组件的方式是“别调用我们,我们会调用你”。

好莱坞原则和模板方法之间的连接其实还算明显:当我们设计模板方法时,我们告诉子类“不要调用我们,我们会调用你”。怎样才能办到呢?让我们再看一次咖啡因饮料的设计:

我们之前还知道一个原则叫依赖倒置原则,好莱坞原则也是有点这个味道的对吧。他们之间的关系是如何的呢?

依赖倒置原则教我们尽量避免使用具体类,而多实用抽象。而好莱坞原则是用在创建框架或组件上的一种技巧,好让低层组件能够被挂钩进计算中,而且又不会让高层组件依赖低层组件。两者的目标都是在于解耦,但是以来倒置原则更加注重如何在设计中避免依赖。

好莱坞原则教我们一个技巧,创建一个有弹性的设计,允许低层结构能够互相操作,而又防止其他类太过于依赖它们。

这样我们就把开篇说的隐藏的原则给介绍完了,也更进一步的知道了模板方法模式钩子的用法,让我们在实战中能有一个更好的选择。这个设计模式,你get到了吗?

小编本来想在这完结的,但是看了下书,发现后面还有一个更贴近实际的,意想不到的模板方法,而且是我们平时会使用到的,我们下篇来聊聊。

爱生活,爱学习,爱感悟,爱挨踢

原文链接:http://www.cnblogs.com/dimple91/p/10959204.html

 友情链接:直通硅谷  点职佳  北美留学生论坛

本站QQ群:前端 618073944 | Java 606181507 | Python 626812652 | C/C++ 612253063 | 微信 634508462 | 苹果 692586424 | C#/.net 182808419 | PHP 305140648 | 运维 608723728

W3xue 的所有内容仅供测试,对任何法律问题及风险不承担任何责任。通过使用本站内容随之而来的风险与本站无关。
关于我们  |  意见建议  |  捐助我们  |  报错有奖  |  广告合作、友情链接(目前9元/月)请联系QQ:27243702 沸活量
皖ICP备17017327号-2 皖公网安备34020702000426号