php设计模式之委托模式


Posted in PHP onFebruary 13, 2016

委托模式是软件设计模式中的一项基本技巧。在委托模式中,有两个对象参与处理同一个请求,接受请求的对象将请求委托给另一个对象来处理。委托模式是一项基本技巧,许多其他的模式,如状态模式、策略模式、访问者模式本质上是在更特殊的场合采用了委托模式。
动态委托的介绍:动态委托概念来自于Jakarta 字节码工程库 (Byte-Code Engineering Library, BCEL)。它能够分析存在的类,并且对于接口,抽象类,甚至运行时的具体类来说,它能够生成以字节编码委托类。
被委托的接口/类应该满足如下条件:动态委托最多只能委托一个类,但是能够代理多个接口。这个限制来自于Java的单继承模式。一个Java类最多只有一个父类。既然生成的委托类把被委托类作为它的父类,那么指定多个被委托类是不合理的。如果没有指定被委托类,那么缺省的父类就是Object。
下面是PHP 反射机制实现动态代理的代码:

<?php
class Fruit

{

  function callFruit()

  {
    print "Generate an Apple";
  }

}

class FruitDelegator
{
 private $targets;
  function __construct()
  {
    $this->target[] = new Fruit();
  }
  
  function __call($name, $args)

  {
    foreach ($this->target as $obj)
    {
      $r = new ReflectionClass($obj);
      if ($method = $r->getMethod($name))

      {

        if ($method->isPublic() && !$method->isAbstract())
        {

          return $method->invoke($obj, $args);
        }

      }

    }
  }

}

$obj = new FruitDelegator();

$obj->callFruit();

// 运行结果

// Generate an Apple
?>

可见,通过代理类FruitDelegator来代替Fruit类来实现他的方法。
同样的,如下的代码也是能够运行的:

<?php
class Color

{
  function callColor()
  {
    print "Generate Red";
  }
}
 

class ColorDelegator

{

  private $targets;

   

  function addObject($obj)

  {

    $this->target[] = $obj;

  }

   

  function __call($name, $args)

  {

    foreach ($this->target as $obj)

    {

      $r = new ReflectionClass($obj);

      if ($method = $r->getMethod($name))

      {

        if ($method->isPublic() && !$method->isAbstract())

        {
          return $method->invoke($obj, $args);
        }
      }
    }
  }
}

$obj = new ColorDelegator();
$obj->addObject(new Color());
$obj->callColor();

?>

设计了一个cd类,类中有mp3播放模式,和mp4播放模式
改进前,使用cd类的播放模式,需要在实例化的类中去判断选择什么方式的播放模式
改进后,播放模式当做一个参数传入playList函数中,就自动能找到对应需要播放的方法。

一、未改进前

<?php 
//使用委托模式之前,调用cd类,选择cd播放模式是复杂的选择过程 
class cd { 
 protected $cdInfo = array(); 
  
 public function addSong($song) { 
  $this->cdInfo[$song] = $song; 
 } 
  
 public function playMp3($song) { 
  return $this->cdInfo[$song] . '.mp3'; 
 } 
  
 public function playMp4($song) { 
  return $this->cdInfo[$song] . '.mp4'; 
 } 
} 
$oldCd = new cd; 
$oldCd->addSong("1"); 
$oldCd->addSong("2"); 
$oldCd->addSong("3"); 
$type = 'mp3'; 
if ($type == 'mp3') { 
 $oldCd->playMp3(); 
} else { 
 $oldCd->playMp4(); 
}

二、通过委托模式,改进后的cd类

<?php
 
namespace Tools;
 
/*
委托模式
去除核心对象中的判决和复杂功能性
*/
 
//委托接口
interface Delegate{
 public function playList($list,$song);
}
 
//mp3处理类
class mp3 implements Delegate{
 public function playList($list,$song){
  return $list[$song].'.mp3';
 }
}
 
//mp4处理类
class mp4 implements Delegate{
 public function playList($list, $song)
 {
  return $list[$song].'.mp4';
 }
}
 
class cdDelegate{
 protected $cdInfo = array();
 
 public function addSong($song){
  $this->cdInfo[$song] = $song;
 }
 
 public function play($type,$song){
  $name = '\Tools\\'.$type;
  $obj = new $name;
  return $obj->playList($this->cdInfo,$song);
 }
}
 
$newCd = new cdDelegate();
$newCd->addSong("1");
$newCd->addSong("2");
$newCd->addSong("3");
echo $newCd->play('mp3','1');//只要传递参数就能知道需要选择何种播放模式

再为大家分享一个实例:

<?php
/**
 * 委托模式 示例
 *
 * @create_date: 2010-01-04
 */
class PlayList
{
 var $_songs = array();
 var $_object = null;
 
 function PlayList($type)
 {
  $object = $type."PlayListDelegation";
  $this->_object = new $object();
 }
 
 function addSong($location,$title)
 {
  $this->_songs[] = array("location"=>$location,"title"=>$title);
 }
 
 function getPlayList()
 {
  return $this->_object->getPlayList($this->_songs);
 }
}
 
class mp3PlayListDelegation
{
 function getPlayList($songs)
 {
  $aResult = array();
  foreach($songs as $key=>$item)
  {
   $path = pathinfo($item['location']);
   if(strtolower($item['extension']) == "mp3")
   {
    $aResult[] = $item;
   }
  }
  return $aResult;
 }
}
 
class rmvbPlayListDelegation
{
 function getPlayList($songs)
 {
  $aResult = array();
  foreach($songs as $key=>$item)
  {
   $path = pathinfo($item['location']);
   if(strtolower($item['extension']) == "rmvb")
   {
    $aResult[] = $item;
   }
  }
  return $aResult;
 }
}
 
$oMP3PlayList = new PlayList("mp3");
$oMP3PlayList->getPlayList();
$oRMVBPlayList = new PlayList("rmvb");
$oRMVBPlayList->getPlayList();
?>

以上就是本文的全部内容,希望对大家的学习有所帮助。

PHP 相关文章推荐
php 生成随机验证码图片代码
Feb 08 PHP
php 5.3.5安装memcache注意事项小结
Apr 12 PHP
php fsockopen伪造post与get方法的详解
Jun 14 PHP
CentOS 6.2使用yum安装LAMP以及phpMyadmin详解
Jun 17 PHP
Windows中使用计划任务自动执行PHP程序实例
May 09 PHP
PHP实现的简单三角形、矩形周长面积计算器分享
Nov 18 PHP
帝国CMS留言板回复后发送EMAIL通知客户
Jul 06 PHP
php5.3后静态绑定用法详解
Nov 11 PHP
php静态成员方法和静态的成员属性的使用方法
Oct 26 PHP
YII框架行为behaviors用法示例
Apr 26 PHP
浅析PHP中的 inet_pton 网络函数
Dec 16 PHP
PHP+Redis事务解决高并发下商品超卖问题(推荐)
Aug 03 PHP
PHP常用设计模式之委托设计模式
Feb 13 #PHP
php判断邮箱地址是否存在的方法
Feb 13 #PHP
php打包网站并在线压缩为zip
Feb 13 #PHP
php session 写入数据库
Feb 13 #PHP
php等比例缩放图片及剪切图片代码分享
Feb 13 #PHP
PHP信号量基本用法实例详解
Feb 12 #PHP
PHP消息队列用法实例分析
Feb 12 #PHP
You might like
PHP小技巧搜集,每个PHPer都来露一手
2007/01/02 PHP
php魔术变量用法实例详解
2014/11/13 PHP
实例讲解通过​PHP创建数据库
2019/01/20 PHP
用Javascript实现UTF8编码转换成gb2312编码
2006/12/22 Javascript
常用一些Javascript判断函数
2012/08/14 Javascript
js动画(animate)简单引擎代码示例
2012/12/04 Javascript
jQuery的3种请求方式$.post,$.get,$.getJSON
2014/03/28 Javascript
js利用prototype调用Array的slice方法示例
2014/06/09 Javascript
JS实现黑客帝国文字下落效果
2015/09/01 Javascript
JS+CSS实现带有碰撞缓冲效果的竖向导航条代码
2015/09/15 Javascript
JavaScript的ExtJS框架中表格的编写教程
2016/05/21 Javascript
【经典源码收藏】基于jQuery的项目常见函数封装集合
2016/06/07 Javascript
jQuery.ajax实现根据不同的Content-Type做出不同的响应
2016/11/03 Javascript
20行JS代码实现粘贴板复制功能
2018/02/06 Javascript
Angular实现模版驱动表单的自定义校验功能(密码确认为例)
2018/05/17 Javascript
浅谈Webpack 是如何加载模块的
2018/05/24 Javascript
详解vue2.0+axios+mock+axios-mock+adapter实现登陆
2018/07/19 Javascript
Vue.js 使用v-cloak后仍显示变量的解决方法
2018/11/19 Javascript
bootstrap下拉分页样式 带跳转页码
2018/12/29 Javascript
详解Vue中的scoped及穿透方法
2019/04/18 Javascript
elementui更改el-dialog关闭按钮的图标d的示例代码
2020/08/04 Javascript
vue基于Echarts的拖拽数据可视化功能实现
2020/12/04 Vue.js
分析经典Python开发工程师面试题
2019/04/08 Python
python的turtle库使用详解
2019/05/10 Python
Django如何开发简单的查询接口详解
2019/05/17 Python
python写程序统计词频的方法
2019/07/29 Python
tensorflow ckpt模型和pb模型获取节点名称,及ckpt转pb模型实例
2020/01/21 Python
如何创建一个Flask项目并进行简单配置
2020/11/18 Python
摩飞电器俄罗斯官方网站:Morphy Richards俄罗斯
2020/07/30 全球购物
追悼会答谢词
2015/01/05 职场文书
安全员岗位职责范本
2015/04/11 职场文书
就业证明函
2015/06/17 职场文书
Java常用工具类汇总 附示例代码
2021/06/26 Java/Android
eval(cmd)与eval($cmd)的区别与联系
2021/07/07 PHP
mysql5.7的安装及Navicate长久免费使用的实现过程
2021/11/17 MySQL
Win11自动黑屏怎么办 Win11自动黑屏设置教程
2022/07/15 数码科技