设计模式 ( 十九 ) 模板方法模式Template method(类行为型)

时间:2022-10-25 21:59:29
  设计模式 ( 十九 ) 模板方法模式Template method(类行为型)

1.概述

在面向对象开发过程中,通常我们会遇到这样的一个问题:我们知道一个算法所需的关键步骤,并确定了这些步骤的执行顺序。但是某些步骤的具体实现是未知的,或者说某些步骤的实现与具体的环境相关。
例子1:银行业务办理流程
在银行办理业务时,一般都包含几个基本固定步骤:
取号排队->办理具体业务->对银行工作人员进行评分。
取号取号排队和对银行工作人员进行评分业务逻辑是一样的。但是办理具体业务是个不相同的,具体业务可能取款、存款或者转账。

2.问题

如何保证架构逻辑的正常执行,而不被子类破坏 ?

3.解决方案

模板方法:定义一个操作中的算法的骨架,而将一些步骤延迟到子类中。 T模板方法使得子类可以不改变一个算法的结构即可重定义该算法的某些特定步骤。(Template Method Pattern:Definethe skeleton of an algorithm in an operation,deferring some steps tosubclasses.Template Methodletssubclasses redefine certain steps of an algorithmwithoutchanging the algorithm's structure. )

1)模板方法模式是基于继承的代码复用基本技术,模板方法模式的结构和用法也是面向对象设计的核心之一。在模板方法模式中,可以将相同的代码放在父类中,而将不同的方法实现放在不同的子类中。
2)在模板方法模式中,我们需要准备一个抽象类,将部分逻辑以具体方法以及具体构造函数的形式实现,然后声明一些抽象方法来让子类实现剩余的逻辑。不同的子类可以以不同的方式实现这些抽象方法,从而对剩余的逻辑有不同的实现,这就是模板方法模式的用意。模板方法模式体现了面向对象的诸多重要思想,是一种使用频率较高的模式。

4.适用性

模板方法应用于下列情况:
• 1) 一次性实现一个算法的不变的部分,并将可变的行为留给子类来实现。
• 2)各子类中公共的行为应被提取出来并集中到一个公共父类中以避免代码重复。首先识别现有代码中的不同之处,并且将不同之处分离为新的操作。最后,用一个调用这些新的操作的模板方法来替换这些不同的代码。
• 3)控制子类扩展。模板方法只在特定点调用“ hook”操作 ,这样就只允许在这些点进行扩展。

5.结构

设计模式 ( 十九 ) 模板方法模式Template method(类行为型)

6.模式的组成

抽象类(AbstractClass): 定义抽象的原语操作(primitive operation) ,具体的子类将重定义它们以实现一个算法, 实现一个模板方法,定义一个算法的骨架。该模板方法不仅调用原语操作,也调用定义
具体子类 (ConcreteClass):  实现原语操作以完成算法中与特定子类相关的步骤。

7.效果

 

模板方法模式的优点:
1)模板方法模式在一个类中形式化地定义算法,而由它的子类实现细节的处理。
2)模板方法是一种代码复用的基本技术。它们在类库中尤为重要,它们提取了类库中的公共行为。
3)模板方法模式导致一种反向的控制结构,这种结构有时被称为“好莱坞法则” ,即“别找我们,,我们找你”通过一个父类调用其子类的操作(而不是相反的子类调用父类),通过对子类的扩展增加新的行为,符合“开闭原则”

模板方法模式的缺点:
每个不同的实现都需要定义一个子类,这会导致类的个数增加,系统更加庞大,设计也更加抽象,但是更加符合“单一职责原则”,使得类的内聚性得以提高。

8.实现

我们使用银行业务实现,添加了hook方法,客户自己觉得评价服务。

  1. <?php
  2. /**
  3. * 模板方法模式:
  4. *
  5. * @author guisu
  6. */
  7. /**
  8. * 抽象类
  9. */
  10. abstract class AbstractBank
  11. {
  12. private $_number ;
  13. /**
  14. *模板方法
  15. * 因为子类不能覆写一个被定义为final的方法。从而保证了子类的逻辑永远由父类所控制。
  16. *
  17. */
  18. public final   function templateMethodProcess()
  19. {
  20. $this->takeNumber();
  21. $this->transact();
  22. if($this->isEvaluateHook()) {
  23. $this->evaluateHook();
  24. }
  25. }
  26. /**
  27. * 基本方法—具体方法
  28. * 取号
  29. *
  30. */
  31. private  function takeNumber()
  32. {
  33. return ++$this->_number;
  34. }
  35. /**
  36. *  //基本方法—抽象方法
  37. *
  38. */
  39. protected  abstract function transact();
  40. /**
  41. * 基本方法—钩子方法
  42. *
  43. */
  44. protected function evaluateHook() {
  45. echo ' evaluateHook<br/>';
  46. }
  47. /**
  48. * 基本方法—钩子方法
  49. */
  50. protected function isEvaluateHook() {
  51. return true;
  52. }
  53. }
  54. /**
  55. * 具体子类:存款
  56. */
  57. class ConcreteDeposit extends AbstractBank
  58. {
  59. public function transact() {
  60. //实现代码
  61. echo 'Deposit', '<br>';
  62. }
  63. }
  64. /**
  65. * 具体子类:取款
  66. */
  67. class ConcreteWithdraw extends AbstractBank
  68. {
  69. public function transact() {
  70. //实现代码
  71. echo 'Withdraw', '<br>';
  72. }
  73. }
  74. /**
  75. * 具体子类:转账
  76. */
  77. class ConcreteTrancfer extends AbstractBank
  78. {
  79. public function transact() {
  80. //实现代码
  81. echo 'Trancfer', '<br>';
  82. }
  83. }
  84. $c = new  ConcreteTrancfer();
  85. $c->templateMethodProcess();

9.与其他相关模式

1)策略模式:模板方法使用继承来改变算法的一部分。 Strategy使用委托来改变整个算法。模板方法模式与策略模式的作用十分类似,有时可以用策略模式替代模板方法模式。模板方法模式通过继承来实现代码复用,而策略模式使用委托,把不确定的行为集中到一个接口中,并在主类委托这个接口。委托比继承具有更大的灵活性。

10.模式的扩展

1)模板方法模式与控制反转(好莱坞原则)在模板方法模式中,子类不显式调用父类的方法,而是通过覆盖父类的方法来实现某些具体的业务逻辑,父类控制对子类的调用,这种机制被称为好莱坞原则(Hollywood Principle),好莱坞原则的定义为:“不要给我们打电话,我们会给你打电话(Don‘t call us, we’ll call you)”。在好莱坞,把简历递交给演艺公司后就只有回家等待。由演艺公司对整个娱乐项的完全控制,演员只能被动式的接受公司的差使,在需要的环节中,完成自己的演出。模板方法模式充分的体现了“好莱坞”原则。由父类完全控制着子类的逻辑,子类不需要调用父类,而通过父类来调用子类,子类可以实现父类的可变部份,却继承父类的逻辑,不能改变业务逻辑。

2)模板方法模式符合开闭原则

模板方法模式意图是由抽象父类控制*逻辑,并把基本操作的实现推迟到子类去实现,这是通过继承的手段来达到对象的复用,同时也遵守了开闭原则。

父类通过*逻辑,它通过定义并提供一个具体方法来实现,我们也称之为模板方法。通常这个模板方法才是外部对象最关心的方法。在上面的银行业务处理例子中,templateMethodProcess这个方法才是外部对象最关心的方法。所以它必须是public的,才能被外部对象所调用。

子类需要继承父类去扩展父类的基本方法,但是它也可以覆写父类的方法。如果子类去覆写了父类的模板方法,从而改变了父类控制的*逻辑,这违反了“开闭原则”。我们在使用模板方法模式时,应该总是保证子类有正确的逻辑。所以模板方法应该定义为final的。所以AbstractClass类的模板方法templateMethodProcess方法应该定义为final。

模板方法模式中,抽象类的模板方法应该声明为final的。因为子类不能覆写一个被定义为final的方法。从而保证了子类的逻辑永远由父类所控制。

3)模板方法模式与对象的封装性

面向对象的三大特性:继承,封装,多态。

对象有内部状态和外部的行为。封装是为了信息隐藏,通过封装来维护对象内部数据的完整性。使得外部对象不能够直接访问一个对象的内部状态,而必须通过恰当的方法才能访问。

对象属性和方法赋予指定的修改符(public、protected、private)来达到封装的目的,使得数据不被外部对象恶意的访问及方法不被错误调用导造成破坏对象的封装性。

降低方法的访问级别,也就是最大化的降低方法的可见度是一种很重要的封装手段。最大化降低方法的可见度除了可以达到信息隐藏外,还能有效的降低类之间的耦合度,降低一个类的复杂度。还可以减少开发人员发生的的错误调用。

一个类应该只公开外部需要调用的方法。而所有为public方法服务的方法都应该声明为protected或private。如是一个方法不是需要对外公开的,但是它需要被子类进行扩展的或调用。那么把它定义为protected.否则应该为private。

显而易见,模板方法模式中的声明为abstract的基本操作都是需要迫使子类去实现的,它们仅仅是为模板方法服务的。它们不应该被抽象类(AbstractClass)所公开,所以它们应该protected。

因此模板方法模式中,迫使子类实现的抽象方法应该声明为protected abstract。

4)模板方法与勾子方法(hookMethod)

模板方法模式的抽象类定义方法:

模板方法:一个模板方法是定义在抽象类中的、把基本操作方法组合在一起形成一个总算法或一个总行为的方法。
基本方法:基本方法是实现算法各个步骤的方法,是模板方法的组成部分。基本方法如下:
抽象方法(Abstract Method)
•具体方法(Concrete Method)
•钩子方法(Hook Method):“挂钩”方法和空方法,
hook方法在抽象类中的实现为空,是留给子类做一些可选的操作。如果某个子类需要一些特殊额外的操作,则可以实现hook方法,当然也可以完全不用理会,因为hook在抽象类中只是空方法而已。
1)钩子方法的引入使得子类可以控制父类的行为。
2)最简单的钩子方法就是空方法,也可以在钩子方法中定义一个默认的实现,如果子类不覆盖钩子方法,则执行父类的默认实现代码。
3)比较复杂一点的钩子方法可以对其他方法进行约束,这种钩子方法通常返回一个boolean类型,即返回true或false,用来判断是否执行某一个基本方法。由子类来决定是否调用hook方法。

11.总结与分析

1)模板方法模式是一种类的行为型模式,在它的结构图中只有类之间的继承关系,没有对象关联关系。
 
2)板方法模式是基于继承的代码复用基本技术,模板方法模式的结构和用法也是面向对象设计的核心之一。在模板方法模式中,可以将相同的代码放在父类中,而将不同的方法实现放在不同的子类中。
3)在模板方法模式中,我们需要准备一个抽象类,将部分逻辑以具体方法以及具体构造函数的形式实现,然后声明一些抽象方法来让子类实现剩余的逻辑。不同的子类可以以不同的方式实现这些抽象方法,从而对剩余的逻辑有不同的实现,这就是模板方法模式的用意。模板方法模式体现了面向对象的诸多重要思想,是一种使用频率较高的模式。

设计模式 ( 十九 ) 模板方法模式Template method(类行为型)的更多相关文章

  1. 模板方法模式 Template method 行为型 设计模式(二十六)

    模板方法模式 Template method 上图为网上百度的一份简历模板截图   相信大家都有求职的经历,那么必然需要简历,写简历的时候,很可能你会网上检索一份简历模板,使用此模板的格式,然后替换为 ...

  2. 二十四种设计模式:模板方法模式&lpar;Template Method Pattern&rpar;

    模板方法模式(Template Method Pattern) 介绍定义一个操作中的算法的骨架,而将一些步骤延迟到子类中.Template Method使得子类可以不改变一个算法的结构即可重定义该算法 ...

  3. 乐在其中设计模式&lpar;C&num;&rpar; - 模板方法模式&lpar;Template Method Pattern&rpar;

    原文:乐在其中设计模式(C#) - 模板方法模式(Template Method Pattern) [索引页][源码下载] 乐在其中设计模式(C#) - 模板方法模式(Template Method ...

  4. 设计模式 - 模板方法模式&lpar;template method pattern&rpar; 具体解释

    模板方法模式(template method pattern) 详细解释 本文地址: http://blog.csdn.net/caroline_wendy 模板方法模式(template metho ...

  5. 设计模式 - 模板方法模式&lpar;template method pattern&rpar; JFrame 具体解释

    模板方法模式(template method pattern) JFrame 具体解释 本文地址: http://blog.csdn.net/caroline_wendy 參考模板方法模式(templ ...

  6. 设计模式 - 模板方法模式&lpar;template method pattern&rpar; 排序&lpar;sort&rpar; 具体解释

    模板方法模式(template method pattern) 排序(sort) 具体解释 本文地址: http://blog.csdn.net/caroline_wendy 參考模板方法模式(tem ...

  7. 模板方法模式&lpar;Template Method Pattern&rpar;——复杂流程步骤的设计

    模式概述 在现实生活中,很多事情都包含几个实现步骤,例如请客吃饭,无论吃什么,一般都包含点单.吃东西.买单等几个步骤,通常情况下这几个步骤的次序是:点单 --> 吃东西 --> 买单. 在 ...

  8. 模板方法模式-Template Method&lpar;Java实现&rpar;

    模板方法模式-Template Method 在模板模式中, 处理的流程被定义在父类中, 而具体的处理则交给了子类. 类关系图很简单: Template接口 这里定义了子类需要实现的方法(before ...

  9. 设计模式 &lpar; 十四 &rpar; 迭代器模式Iterator(对象行为型)

      设计模式 ( 十四 ) 迭代器模式Iterator(对象行为型) 1.概述 类中的面向对象编程封装应用逻辑.类,就是实例化的对象,每个单独的对象都有一个特定的身份和状态.单独的对象是一种组织代码的 ...

随机推荐

  1. Python3使用urllib访问网页

    介绍 改教程翻译自python官网的一篇文档. urllib.request是一个用于访问URL(统一资源定位符)的Python模块.它以urlopen函数的形式提供了一个非常简单的接口,可以访问使用 ...

  2. CentOS&lowbar;7&period;2服务器前期

    一.禁用SELinux:# 永久禁用,需要重启生效: sed -i 's/SELINUX=enforcing/SELINUX=disabled/g' /etc/sysconfig/selinux se ...

  3. TCP发消息续传文件

    1.自定义固定协议头部.格式:([head][body][filestream]) /// <summary> /// 数据包头部 /// </summary> [Struct ...

  4. Directx 3D编程实例:绘制3DMesh

    最近朋友建议我写一些关于微软云技术的博客留给学校下一届的学生们看,怕下一届的MSTC断档.于是我也觉的有这个必要.写了几篇博客之后,我觉得也有必要把这一年的学习内容放在博客做个纪念,就这样写了本篇博客 ...

  5. Hibernate中HQL的日期差值计算,可计算相差多少秒

    最近有个业务需求就是计算订单创建时间离现在超过 4 小时的订单都查找出来! 那么就需要用到日期函数了. 网上找了一下总共的日期函数有一下几个: CURRENT_DATE() 返回数据库当前日期 时间函 ...

  6. Java之定时任务详解

    在我们编程过程中如果需要执行一些简单的定时任务,无须做复杂的控制,我们可以考虑使用JDK中的Timer定时任务来实现.下面就其原理.实例以及Timer缺陷三个方面来解析java Timer定时器. 在 ...

  7. Oracle backgroup processes

    PMON: Process Monitor 用自己主动注冊动态监听,处理异常进程. SMON: System Monitor 用于instance recovery. LCKn:仅使用于RAC数据库, ...

  8. Ubuntu18&period;04格式化U盘为NTFS的方法

    1.先安装工具ntfs-3g sudo apt-get install ntfs-3g 2.找到需要格式化的U盘在系统中的序号 df -h 找到U盘的序列号后记下来,例如“/dev/sdd1” 3.解 ...

  9. 『2019&sol;4&sol;9 TGDay2模拟赛 反思与总结』

    2019/4/9 TGDay2模拟赛 今天是\(TG\)模拟赛的第二天了,试题难度也是相应地增加了一些,老师也说过,这就是提高组的难度了.刚开始学难的内容,一道正解也没想出来,不过基本的思路也都是对了 ...

  10. 减少xcode错误输出

    运行xcrun相关命令如果出现找不到对应模块和工具,要确认一下在xcode中命令行工具是否正确设置了 xcrun simctl spawn booted log config --mode &quot ...