php设计模式之委托模式

5年以前  |  阅读数:902 次  |  编程语言:PHP 

委托模式是软件设计模式中的一项基本技巧。在委托模式中,有两个对象参与处理同一个请求,接受请求的对象将请求委托给另一个对象来处理。委托模式是一项基本技巧,许多其他的模式,如状态模式、策略模式、访问者模式本质上是在更特殊的场合采用了委托模式。
动态委托的介绍:动态委托概念来自于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分页显示制作详细讲解
SSH 登录失败:Host key verification failed
获取IMSI
将二进制数据转为16进制以便显示
获取IMEI
文件下载
贪吃蛇
双位运算符
PHP自定义函数获取搜索引擎来源关键字的方法
Java生成UUID
发送邮件
年的日历图
提取后缀名
在Zeus Web Server中安装PHP语言支持
让你成为最历害的git提交人
Yii2汉字转拼音类的实例代码
再谈PHP中单双引号的区别详解
指定应用ID以获取对应的应用名称
Python 2与Python 3版本和编码的对比
php封装的page分页类完整实例