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学习资源和链接.
Dec 05 PHP
PHP UTF8中文字符截断函数代码
Sep 11 PHP
php中计算程序运行时间的类代码
Nov 03 PHP
php获取用户IPv4或IPv6地址的代码
Nov 15 PHP
浅谈php函数serialize()与unserialize()的使用方法
Aug 19 PHP
php以post形式发送xml的方法
Nov 04 PHP
php文件缓存类汇总
Nov 21 PHP
php转换颜色为其反色的方法
Apr 27 PHP
再Docker中架设完整的WordPress站点全攻略
Jul 29 PHP
PHP explode()函数的几个应用和implode()函数有什么区别
Nov 05 PHP
浅析Laravel5中队列的配置及使用
Aug 04 PHP
Yii框架实现图片上传的方法详解
May 20 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
DOTA2 6.87版本后新眼位详解攻略
2020/04/20 DOTA
绿山咖啡和蓝山咖啡
2021/03/04 新手入门
php将print_r处理后的数据还原为原始数组的解决方法
2016/11/02 PHP
ArrayList类(增强版)
2007/04/04 Javascript
javascript 数组排序函数
2009/08/20 Javascript
javascript的字符串按引用复制和传递,按值来比较介绍与应用
2012/12/28 Javascript
使用JavaScript 实现各种跨域的方法
2013/05/08 Javascript
jQuery jcrop插件截图使用方法
2013/11/20 Javascript
jQuery ajax serialize() 方法使用示例
2014/11/02 Javascript
跟我学习javascript创建对象(类)的8种方法
2015/11/20 Javascript
Javascript技术难点之apply,call与this之间的衔接
2015/12/04 Javascript
对象转换为原始值的实现方法
2016/06/06 Javascript
Vuex之理解Getters的用法实例
2017/04/19 Javascript
angular+ionic返回上一页并刷新页面
2017/08/08 Javascript
详解React服务端渲染从入门到精通
2019/03/28 Javascript
如何为你的JavaScript代码日志着色详解
2019/04/08 Javascript
利用不到200行代码写一款属于你自己的js类库
2019/07/08 Javascript
vue+element导航栏高亮显示的解决方式
2019/11/12 Javascript
JavaScript DOM常用操作代码汇总
2020/07/03 Javascript
JS中的变量作用域(console版)
2020/07/18 Javascript
详解JavaScript中的链式调用
2020/11/27 Javascript
vue-router定义元信息meta操作
2020/12/07 Vue.js
[55:44]完美世界DOTA2联赛决赛 FTD vs Phoenix 第二场 11.08
2020/11/11 DOTA
Python常用小技巧总结
2015/06/01 Python
Python应用库大全总结
2018/05/30 Python
Python使用matplotlib和pandas实现的画图操作【经典示例】
2018/06/13 Python
python绘制漏斗图步骤详解
2019/03/04 Python
Python 实现交换矩阵的行示例
2019/06/26 Python
浅谈python3打包与拆包在函数的应用详解
2020/05/02 Python
匡威西班牙官网:Converse西班牙
2019/10/01 全球购物
Fnac西班牙官网:法国文化和电子产品零售商
2021/03/14 全球购物
会计演讲稿范文
2014/05/23 职场文书
思想道德自我评价2015
2015/03/09 职场文书
2015年妇联工作总结范文
2015/04/22 职场文书
详解Java实现数据结构之并查集
2021/06/23 Java/Android
html网页引入svg图片的4种方式
2022/08/05 HTML / CSS