代理模式

代理模式

为其他对象提供一种代理以控制对这个对象的访问。

代理模式是对象的结构模式,代理模式给某一个对象提供一个代理对象,并由此代理对象控制对原代理对象的引用。代理模式不应该让用户感觉到代理的存在,所以代理对象和原对象的对外的调用接口是一致的。

 

代理模式一般包括三个角色:

 

  • 抽象主题角色(Subject):它的作用是统一接口。此角色定义了真实主题角色和代理主题角色共用的接口,这样就可以在使用真实主题角色的地方使用代理主题角色。
  • 真实主题角色(RealSubject):隐藏在代理角色后面的真实对象。
  • 代理主题角色(ProxySubject):它的作用是代理真实主题,在其内部保留了对真实主题角色的引用。它与真实主题角色都继承自抽象主题角色,保持接口的统一。它可以控制对真实主题的存取,并可能负责创建和删除真实对象。代理角色并不是简单的转发,通常在将调用传递给真实对象之前或之后执行某些操作,当然你也可以只是简单的转发。 与适配器模式相比:适配器模式是为了改变对象的接口,而代理模式并不能改变所代理对象的接口。

 

 

思维导图:

 

使用场景:实现延迟加载。

 

<?php/**
 * Proxy design pattern (lazy loading)@global
 * 实现了图片的延迟加载
 */

/* 抽象主题角色,提供统一接口 */
interface ImageInterface
{
    public function display();
}

/* 真是主题角色,就是需要被代理的类 */
class Image implements ImageInterface
{
    protected $filename;
    public function  __construct($filename) {
        $this->filename = $filename;
        $this->loadFromDisk();
    }
    protected function loadFromDisk() {
        echo "Loading {$this->filename}\n";
    }
    public function display() {
        echo "Display {$this->filename}\n";
    }
}

/* 代理主题角色,原图片类在实例化时就把图片加载到内存了,用代理修改为display时才执行加载 */
class ProxyImage implements ImageInterface
{
    protected $id;
    protected $image;
    protected $filename;

    public function  __construct($filename) {
        $this->filename = $filename;
    }
    public function display() {
        if (null === $this->image) { //缓存
            $this->image = new Image($this->filename);

        }
        return $this->image->display();
    }
}

//调用Image类,在实例化时就加载到内存了,如果没调display就浪费了
$filename = 'test.png';
$image1 = new Image($filename); // 已经加载到内存
echo $image1->display();

//代理类是在display时才把图片从磁盘加入内存
$image2 = new ProxyImage($filename);
echo $image2->display(); // 此时才加载到内存
echo $image2->display(); // 直接从内存获取

 

通过反射来代理多个对象,这种方式有缺陷,看代码体会!具体使用还看应用场景

<?PHP
/**
 * 使用反射实现代理工厂
 */

/**
 * 真实主题角色 A
 */
final class RealSubjectA {

    public function __construct() {
    }

    public function actionA() {
        echo "actionA method in RealSubject A <br />\r\n";
    }

}

/**
 * 真实主题角色 B
 */
final class RealSubjectB {

    public function __construct() {
    }

    public function actionB() {
        echo "actionB method in RealSubject B <br />\r\n";
    }

}

/**
 * 代理主题角色
 */
final class ProxySubject {

    private $_real_subjects = NULL;

    public function __construct() {
        $this->_real_subjects = array();
    }

    /**
     * 动态添加真实主题
     * @param type $subject
     */
    public function addSubject($subject) {
        $this->_real_subjects[] = $subject;
    }

    public function __call($name, $args) {
        foreach ($this->_real_subjects as $real_subject) {

            /* 使用反射获取类及方法相关信息  */
            $reflection = new ReflectionClass($real_subject);

            /* 如果不存在此方法,下一元素 */
            if (!$reflection->hasMethod($name)) {
                continue;
            }

            $method = $reflection->getMethod($name);

            /* 判断方法是否为公用方法并且是否不为抽象方法 */
            if ($method && $method->isPublic() && !$method->isAbstract()) {
                $this->_beforeAction();

                $method->invoke($real_subject, $args);

                $this->_afterAction();

                break;
            }
        }
    }

    /**
     * 请求前的操作
     */
    private function _beforeAction() {
        echo "Before action in ProxySubject<br />\r\n";
    }

    /**
     * 请求后的操作
     */
    private function _afterAction() {
        echo "After action in ProxySubject<br />\r\n";
    }

}


$subject = new ProxySubject();

$subject->addSubject(new RealSubjectA());
$subject->addSubject(new RealSubjectB());

$subject->actionA();
$subject->actionB();

 

posted @ 2014-12-17 18:32  leezhxing  阅读(295)  评论(0编辑  收藏  举报