PHP设计模式之模板方法模式定义与用法详解


Posted in PHP onApril 02, 2018

本文实例讲述了PHP设计模式之模板方法模式定义与用法。分享给大家供大家参考,具体如下:

什么是模板方法模式

模板方法(Template Method)设计模式中使用了一个类方法templateMethod(), 该方法是抽象类中的一个具体方法, 这个方法的作用是对抽象方法序列排序,具体实现留给具体类来完成.关键在于模板方法模式定义了操作中算法的"骨架",而由具体类来实现.

什么时候使用模板方法

如果已经明确算法中的一些步骤, 不过这些步骤可以采用多种不同的方法实现, 就可以使用模板方法调试.如果算法中的步骤不变, 可以把这些步骤留给子类具体实现.在这种情况下, 可以使用模板方法设计模式来组织抽象类中的基本操作(函数/方法).然后由子类来实现应用所需的这些操作.

还有一种用法稍微复杂一些, 可能需要把子类共同的行为放在一个类中, 以避免代码重复.

如果使用多个类来解决同一个大型问题, 可能很快就会出现重复代码.

还有一点,可以使用模板方法模式控制子类扩展,也就是所谓的"钩子".

示例

在PHP编程中,可能经常会遇到一个问题: 要建立带图题的图像. 这个算法相当简单, 就是显示图像, 然后的图像下面显示文本.

由于模板设计中只涉及两个参与者, 所以这是最容易理解的模式之一, 同时也非常有用. 抽象建立templateMethod(),并由具体类实现这个方法.

抽象类

抽象类是这里的关键, 因为它同时包含具体和抽象方法. 模板方法往往是具体方法, 其操作是抽象的

两个抽象方法分别是addPicture和addTitile,这两个操作都包含一个参数, 分别表示图像的URL信息和图像标题.

Template.php

<?php
abstract class Template
{
  protected $picture;
  protected $title;
  public function display($pictureNow, $titleNow)
  {
    $this->picture = $pictureNow;
    $this->title = $titleNow;
    $this->addPicture($this->picture);
    $this->addTitle($this->title);
  }
  abstract protected function addPicture($picture);
  abstract protected function addTitle($title);
}

具体类

Concrete.php

<?php
include_once('Template.php');
class Concrete extends Template
{
  protected function addPicture($picture)
  {
    $this->picture = 'picture/' . $picture;
    echo "图像路径为:" . $this->picture . '<br />';
  }
  protected function addTitle($title)
  {
    $this->title = $title;
    echo "<em>标题: </em>" . $this->title . "<br />";
  }
}

客户

Client.php

<?php
function __autoload($class_name)
{
  include $class_name . '.php';
}
class Client
{
  public function __construct()
  {
    $title = "chenqionghe is a handsome boy";
    $concrete = new Concrete();
    $concrete->display('chenqionghe.png', $title);
  }
}
$worker = new Client();

$concrete变量实例化了Concrete, 但是它调用了display模板方法, 这是从父类继承的具体操作, 父类通过display()调用子类的操作.

运行后输出

图像路径为:picture/chenqionghe.png
标题: chenqionghe is a handsome boy

可以看到,客户只需要提供图像地址和标题

模板方法设计模式中的钩子

有时模板方法函数可能有一个你不想要的步骤, 某些特定情况下你可能不希望执行这个步骤, 这时候就可以用到模板方法的钩子.

在模板方法设计模式中, 利用钩子可以将一个方法作为模板的一部分,不过不一定会用到这个方法, 换句话说, 它是方法的一部分,不过它包含一个钩子, 可以处理例外情况. 子类可以为算法增加一个可选元素, 这样一来, 尽管仍按模板方法建立的顺序执行, 但有可能并不完成模板方法期望的动作. 对于这种可选的情况, 钩子就是解决这个问题最理想的工具.

示例

去网购商品, 登场8折, 如果总商品费用超过200元, 就免去12.95元钱运费.

建立钩子

在模板方法中建立钩子方法很有意思, 尽管子类可以改变钩子的行为, 但仍然要遵循模板中定义的顺序

IHook.php

<?php
abstract class IHook
{
  protected $hook;
  protected $fullCost;
  public function templateMethod($fullCost, $hook)
  {
    $this->fullCost = $fullCost;
    $this->hook = $hook;
    $this->addGoods();
    $this->addShippingHook();
    $this->displayCost();
  }
  protected abstract function addGoods();
  protected abstract function addShippingHook();
  protected abstract function displayCost();
}

这里有3个抽象方法: addGoods(), addShippingHook(),displayCost(), 抽象类IHook实现的templateMethod()中确定了它们的顺序. 在这里, 钩子方法放在中间, 实际上模板方法指定的顺序中, 钩子可以放在任意位置. 模板方法需要两个参数, 一个是总花费, 另外还需要一个变量用来确定顾客是否免收运费.

实现钩子

一旦抽象类中建立了这些抽象方法, 并指定了它们执行的顺序, 子类将实现所有这3个方法:

Concrete.php

<?php
class Concrete extends IHook
{
  protected function addGoods()
  {
    $this->fullCost = $this->fullCost * 0.8;
  }
  protected function addShippingHook()
  {
    if(!$this->hook)
    {
      $this->fullCost += 12.95;
    }
  }
  protected function displayCost()
  {
    echo "您需要支付: " . $this->fullCost . '元<br />';
  }
}

addGoods和displayCost都是标准方法, 只有一个实现., 不过, addShippingHook的实现有所不同, 其中有一个条件来确定是否增加运费. 这就是钩子.

客户Client

Client.php

<?php
function __autoload($class_name)
{
  include $class_name . '.php';
}
class Client
{
  private $totalCost;
  private $hook;
  public function __construct($goodsTotal)
  {
    $this->totalCost = $goodsTotal;
    $this->hook = $this->totalCost >= 200;
    $concrete = new Concrete();
    $concrete->templateMethod($this->totalCost, $this->hook);
  }
}
$worker = new Client(100);
$worker = new Client(200);

该Client演示了分别购买100块钱和200块钱的商品最后的费用,运行结果如下

您需要支付: 92.95元
您需要支付: 160元

希望本文所述对大家PHP程序设计有所帮助。

PHP 相关文章推荐
ADODB的数据库封包程序库
Dec 31 PHP
一个自定义位数的php多用户计数器代码
Mar 11 PHP
PHP 上传文件大小限制
Jul 05 PHP
PHP程序员最常犯的11个MySQL错误小结
Nov 20 PHP
美图秀秀web开放平台--PHP流式上传和表单上传示例分享
Jun 22 PHP
在html文件中也可以执行php语句的方法
Apr 09 PHP
php封装的验证码工具类完整实例
Oct 19 PHP
php  PATH_SEPARATOR判断当前服务器系统类型实例
Oct 28 PHP
php+redis实现多台服务器内网存储session并读取示例
Jan 12 PHP
laravel框架邮箱认证实现方法详解
Nov 22 PHP
ThinkPHP3.1.2 使用cli命令行模式运行的方法
Apr 14 PHP
php的单例模式及应用场景详解
Feb 27 PHP
PHP实现动态获取函数参数的方法示例
Apr 02 #PHP
PHP调用其他文件中的类
Apr 02 #PHP
为何说PHP引用是个坑,要慎用
Apr 02 #PHP
PHP实现的一致性Hash算法详解【分布式算法】
Mar 31 #PHP
PHP实现基于PDO扩展连接PostgreSQL对象关系数据库示例
Mar 31 #PHP
ThinkPHP框架中使用Memcached缓存数据的方法
Mar 31 #PHP
PHPTree――php快速生成无限级分类
Mar 30 #PHP
You might like
落伍首发 php+mysql 采用ajax技术的 省 市 地 3级联动无刷新菜单 源码
2006/12/16 PHP
一个PHP的String类代码
2010/04/20 PHP
一个PHP针对数字的加密解密类
2014/03/20 PHP
php绘制圆形的方法
2015/01/24 PHP
php强大的时间转换函数strtotime
2016/02/18 PHP
PHP实现给定一列字符,生成指定长度的所有可能组合示例
2019/06/22 PHP
jQuery的写法不同导致的兼容性问题的解决方法
2010/07/29 Javascript
检测input每次的输入是否合法遇到汉字输入就有问题
2012/05/23 Javascript
js实现页面跳转重定向的几种方式
2014/05/29 Javascript
json对象转为字符串,当做参数传递时加密解密的实现方法
2016/06/29 Javascript
AngularJS使用ng-inlude指令加载页面失败的原因与解决方法
2017/01/19 Javascript
Vue关于数据绑定出错解决办法
2017/05/15 Javascript
react-redux中connect的装饰器用法@connect详解
2018/01/13 Javascript
关于HTML5的data-*自定义属性的总结
2018/05/05 Javascript
微信小程序接入腾讯云验证码的方法步骤
2020/01/07 Javascript
JS localStorage存储对象,sessionStorage存储数组对象操作示例
2020/02/15 Javascript
利用Python的Twisted框架实现webshell密码扫描器的教程
2015/04/16 Python
python使用pil生成图片验证码的方法
2015/05/08 Python
python 读取摄像头数据并保存的实例
2018/08/03 Python
pyqt远程批量执行Linux命令程序的方法
2019/02/14 Python
使用Python3内置文档高效学习以及官方中文文档
2019/05/19 Python
Django项目创建到启动详解(最全最详细)
2019/09/07 Python
python使用 request 发送表单数据操作示例
2019/09/25 Python
Python协程 yield与协程greenlet简单用法示例
2019/11/22 Python
如何使用python记录室友的抖音在线时间
2020/06/29 Python
python之语音识别speech模块
2020/09/09 Python
浅谈CSS3 box-sizing 属性 有趣的盒模型
2019/04/02 HTML / CSS
记一次高分屏下canvas模糊问题
2020/02/17 HTML / CSS
质检的岗位职责
2013/11/17 职场文书
8和9的加减法教学反思
2014/05/01 职场文书
领导干部学习“三严三实”思想汇报
2014/09/15 职场文书
2014超市收银员工作总结
2014/11/13 职场文书
党员承诺书范文2015
2015/04/27 职场文书
使用pycharm运行flask应用程序的详细教程
2021/06/07 Python
七个非常实用的Python工具包总结
2021/06/15 Python
java后台调用接口及处理跨域问题的解决
2022/03/24 Java/Android