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 相关文章推荐
连接到txt文本的超链接,不直接打开而是点击后下载的处理方法
Jul 01 PHP
PHP 创建文件(文件夹)以及目录操作代码
Mar 04 PHP
PHP中strtotime函数使用方法详解
Nov 27 PHP
SESSION信息保存在哪个文件目录下以及能够用来保存什么类型的数据
Jun 17 PHP
关于尾递归的使用详解
May 02 PHP
解析posix与perl标准的正则表达式区别
Jun 17 PHP
PHP URL参数获取方式的四种例子
Feb 28 PHP
php求正负数数组中连续元素最大值示例
Apr 11 PHP
Smarty实现页面静态化(生成HTML)的方法
May 23 PHP
php获取网站根目录物理路径的几种方法(推荐)
Mar 04 PHP
PHP实现的mysql主从数据库状态检测功能示例
Jul 20 PHP
laravel框架使用阿里云短信发送消息操作示例
Feb 15 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
IIS下配置Php+Mysql+zend的图文教程
2006/12/08 PHP
PHP Ajax中文乱码问题解决方法
2009/02/27 PHP
PHP生成json和xml类型接口数据格式
2015/05/17 PHP
一段多浏览器的&quot;复制到剪贴板&quot;javascript代码
2007/03/27 Javascript
jquery下动态显示jqGrid以及jqGrid的属性设置容易出现问题的解决方法
2010/10/22 Javascript
11款新鲜的jQuery插件[附所有demo下载]
2011/01/24 Javascript
原生js实现可拖动的登录框效果
2017/01/21 Javascript
原生js更改css样式的两种方式
2017/03/15 Javascript
JS对象与JSON互转换、New Function()、 forEach()、DOM事件流等js开发基础小结
2017/08/10 Javascript
如何理解Vue的作用域插槽的实现原理
2017/08/19 Javascript
JavaScript面向对象继承原理与实现方法分析
2018/08/09 Javascript
微信小程序支付PHP代码
2018/08/23 Javascript
解决vue v-for src 图片路径问题 404
2019/11/12 Javascript
微信小程序后端(java)开发流程的详细步骤
2019/11/13 Javascript
[01:54]TI4西雅图DOTA2选手欢迎晚宴 现场报道
2014/07/08 DOTA
下载安装setuptool和pip linux安装pip    
2014/01/24 Python
python实现多线程暴力破解登陆路由器功能代码分享
2015/01/04 Python
Python中的random()方法的使用介绍
2015/05/15 Python
python结合selenium获取XX省交通违章数据的实现思路及代码
2016/06/26 Python
python字典排序的方法
2019/10/12 Python
Django 实现 Websocket 广播、点对点发送消息的代码
2020/06/03 Python
python logging模块的使用
2020/09/07 Python
Python利用myqr库创建自己的二维码
2020/11/24 Python
python中Mako库实例用法
2020/12/31 Python
CSS Houdini实现动态波浪纹效果
2019/07/30 HTML / CSS
设计师珠宝:Ylang 23
2018/05/11 全球购物
千禧酒店及度假村官方网站:Millennium Hotels and Resorts
2019/05/10 全球购物
以太网Ethernet IEEE802.3
2013/08/05 面试题
农贸市场管理制度
2014/01/31 职场文书
《傅雷家书》教学反思
2014/04/20 职场文书
工作期间打牌检讨书范文
2014/11/20 职场文书
2015初一年级组工作总结
2015/07/24 职场文书
小学教师教学随笔
2015/08/14 职场文书
2016年党校科级干部培训班学习心得体会
2016/01/06 职场文书
中秋节作文(五年级)之关于月亮
2019/09/11 职场文书
Django REST framework 限流功能的使用
2021/06/24 Python