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 删除记录实现代码
Mar 12 PHP
把1316这个数表示成两个数的和,其中一个为13的倍数,另一个是11的倍数,求这两个数。
Jun 24 PHP
判断PHP数组是否为空的代码
Sep 08 PHP
PHP仿盗链代码
Jun 03 PHP
thinkphp3.0 模板中函数的使用
Nov 13 PHP
php中数字0和空值的区别分析
Jun 05 PHP
PHP中通过fopen()函数访问远程文件示例
Nov 18 PHP
php+jQuery.uploadify实现文件上传教程
Dec 26 PHP
php中curl使用指南
Feb 05 PHP
CentOS安装php v8js教程
Feb 26 PHP
PHP入门教程之面向对象的特性分析(继承,多态,接口,抽象类,抽象方法等)
Sep 11 PHP
php接口实现拖拽排序功能
Apr 23 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面向对象全攻略 (十四) php5接口技术
2009/09/30 PHP
PHP+Ajax实现的无刷新分页功能详解【附demo源码下载】
2017/07/03 PHP
PHP大文件分割上传 PHP分片上传
2017/08/28 PHP
PHP中define() 与 const定义常量的区别详解
2019/06/25 PHP
PHP中非常有用却鲜有人知的函数集锦
2019/08/17 PHP
统计jQuery中各字符串出现次数的工具
2012/05/03 Javascript
兼容FF和IE的动态table示例自写
2013/10/21 Javascript
用jquery实现的一个超级简单的下拉菜单
2014/05/18 Javascript
JQuery中节点遍历方法实例
2015/05/18 Javascript
Javascript类型转换的规则实例解析
2016/02/23 Javascript
浅析C/C++,Java,PHP,JavaScript,Json数组、对象赋值时最后一个元素后面是否可以带逗号
2016/03/22 Javascript
BootStrap的JS插件之轮播效果案例详解
2016/05/16 Javascript
js无提示关闭浏览器窗口的两种方法分析
2016/11/06 Javascript
JavaScript组件开发之输入框加候选框
2017/03/10 Javascript
vue上传图片组件编写代码
2017/07/26 Javascript
微信小程序chooseImage的用法(从本地相册选择图片或使用相机拍照)
2018/08/22 Javascript
Vue页面跳转动画效果的实现方法
2018/09/23 Javascript
d3绘制基本的柱形图的实现代码
2018/12/12 Javascript
cocos2dx+lua实现橡皮擦功能
2018/12/20 Javascript
Vue.extend实现挂载到实例上的方法
2019/05/01 Javascript
JS图片懒加载的优点及实现原理
2020/01/10 Javascript
Python读写unicode文件的方法
2015/07/10 Python
PyTorch快速搭建神经网络及其保存提取方法详解
2018/04/28 Python
运行django项目指定IP和端口的方法
2018/05/14 Python
python使用thrift教程的方法示例
2019/03/21 Python
基于Python打造账号共享浏览器功能
2019/05/30 Python
解决python ThreadPoolExecutor 线程池中的异常捕获问题
2020/04/08 Python
Tensorflow安装问题: Could not find a version that satisfies the requirement tensorflow
2020/04/20 Python
浅谈CSS3特性查询(Feature Query: @supports)功能简介
2017/07/31 HTML / CSS
多视角3D可旋转的HTML5 Logo动画
2016/03/02 HTML / CSS
阿里巴巴国际站:Alibaba.com
2016/07/21 全球购物
计算 s=(x*y)1/2,用两个宏定义来实现
2016/08/11 面试题
护士的自我鉴定
2014/02/07 职场文书
药品促销活动方案
2014/02/14 职场文书
幼儿园教师自我评价
2015/03/04 职场文书
元素水平垂直居中的方式
2021/03/31 HTML / CSS