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 相关文章推荐
PHP概述.
Oct 09 PHP
在Zeus Web Server中安装PHP语言支持
Oct 09 PHP
《PHP边学边教》(01.开篇――准备工作)
Dec 13 PHP
phpmyadmin里面导入sql语句格式的大量数据的方法
Jun 05 PHP
深入php常用函数的使用汇总
Jun 08 PHP
Codeigniter框架的更新事务(transaction)BUG及解决方法
Jul 25 PHP
php set_include_path函数设置 include_path 配置选项
Oct 30 PHP
php 判断字符串编码是utf-8 或gb2312实例
Nov 01 PHP
php实现网页端验证码功能
Jul 11 PHP
tp5(thinkPHP5)框架实现多数据库查询的方法
Jan 10 PHP
Thinkphp页面跳转设置跳转等待时间的操作
Oct 16 PHP
宝塔面板出现“open_basedir restriction in effect. ”的解决方法
Mar 14 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 的异常处理、错误的抛出及回调函数等面向对象的错误处理方法
2012/12/07 PHP
php计算指定目录下文件占用空间的方法
2015/03/13 PHP
Nginx下ThinkPHP5的配置方法详解
2017/08/01 PHP
用 JSON 处理缓存
2007/04/27 Javascript
建立良好体验度的Web注册系统ajax
2007/07/09 Javascript
科讯商业版中用到的ajax空间与分页函数
2007/09/02 Javascript
javascript DOM编程实例(智播客学习)
2009/11/23 Javascript
判断目标是否是window,document,和拥有tagName的Element的代码
2010/05/31 Javascript
在标题栏显示新消息提示,很多公司项目中用到这个方法
2011/11/04 Javascript
遍历DOM对象内的元素属性示例代码
2014/02/08 Javascript
js中iframe调用父页面的方法
2014/10/30 Javascript
jQuery插件jFade实现鼠标经过的图片高亮其它变暗
2015/03/14 Javascript
Bootstrap4一次重大更新 几乎涉及每行代码
2016/05/16 Javascript
Javascript动画效果(4)
2016/10/11 Javascript
Jquery表单验证失败后不提交的解决方法
2016/10/18 Javascript
vue 全选与反选的实现方法(无Bug 新手看过来)
2018/02/09 Javascript
vue-image-crop基于Vue的移动端图片裁剪组件示例
2018/08/28 Javascript
H5+C3+JS实现双人对战五子棋游戏(UI篇)
2020/05/28 Javascript
Jquery实现获取子元素的方法分析
2019/08/24 jQuery
使用pkg打包ThinkJS项目的方法步骤
2019/12/30 Javascript
[05:00]第二届DOTA2亚洲邀请赛主赛事第三天比赛集锦.mp4
2017/04/04 DOTA
python logging类库使用例子
2014/11/22 Python
使用Python绘制图表大全总结
2017/02/11 Python
使用tensorflow实现线性回归
2018/09/08 Python
pandas通过索引进行排序的示例
2018/11/16 Python
anaconda中更改python版本的方法步骤
2019/07/14 Python
Jupyter notebook 远程配置及SSL加密教程
2020/04/14 Python
澳大利亚领先的在线葡萄酒零售商:Get Wines Direct
2018/03/27 全球购物
外企求职信范文分享
2013/12/31 职场文书
市场部管理制度
2014/02/02 职场文书
公路绿化方案
2014/05/12 职场文书
党员学习党的群众路线思想汇报(5篇)
2014/09/10 职场文书
2014光棍节大学生联谊活动方案
2014/10/10 职场文书
2014年科室工作总结范文
2014/12/19 职场文书
小学教师自我评价
2015/03/04 职场文书
离婚撤诉申请书范本
2015/05/18 职场文书