您的位置:首页 > 编程语言 > PHP开发

PHP设计模式:结构型之代理(Proxy)

2014-06-22 14:56 741 查看
代理模式(Proxy)

<意图>

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

  代理模式给某一个对象提供一个代理对象,并由代理对象控制对源对象(被代理对象)的引用。代理就是一个人或一个机构代表另一个人或者一个机构采取行动。 (客户端引用的是代理对象)某些情况下,客户不想或者不能够直接引用一个对象,代理对象可以在客户和目标对象直接起到中介的作用。客户端分辨不出代理主题 对象与真实主题对象。代理模式可以并不知道真正的被代理对象,而仅仅持有一个被代理对象的接口,这时候代理对象不能够创建被代理对象,被代理对象必须有系 统的其他角色代为创建并传入。

<动机>

  因为某个对象消耗太多资源,而且你的代码并不是每个逻辑路径都需要此对象, 你曾有过延迟创建对象的想法吗 ( if和else就是不同的两条逻辑路径) ? 你有想过限制访问某个对象,也就是说,提供一组方法给普通用户,特别方法给管理员用户?以上两种需求都非常类似,并且都需要解决一个更大的问题:你如何提供一致的接口给某个对象让它可以改变其内部功能,或者是从来不存在的功能?

  你怎样才能在不直接操作对象的情况下,对此对象进行访问?

<UML>



<总结>

  个人理解实际应用中就是相当于公有的放到一个类中,客户访问不到,但是适当的时候需要调用,特殊的私有的放在各自类中用到时调用。特殊的类就是代理类需要有公有类的引用。只需要在用到的时候才取, client只需要引用代理对象。

两种情况:

  一、引用不到寻求代理。

  二、聚合共用部分,用到才调用,与继承相比增加对象开销但调用快,代码可复用。

<代理模式与父类和接口的异同>

<相同点>

  代理模式的作用和父类以及接口的作用类似,都是为了聚合共用部分,减少公共部分的代码。

<不同点>

  相比起父类,他们的语境不同,父类要表达的含义是 is-a, 而代理要表达的含义更接近于接口, 是 has-a,而且使用代理的话应了一句话"少用继承,多用组合",要表达的意思其实也就是降低耦合度了。

  相比起接口,他们实现的功能又不太一样,语境都是has-a,不过接口是has-a-function,而代理对象时是has-a-object,这个 object是has-a-function的object,此外,接口是为了说明这个类拥有什么功能,却没有具体实现,实现了多态,而代理对象不但拥有 这个功能,还拥有这个功能的具体实现。

[b]<示例一>[/b]

class Subject {
function someMethod() {
echo "test";
//sleep(1); //do something
}
}

class ProxySubject {
private $subject;
function ProxySubject() {
$this->subject = new Subject();
}
function someMethod() {
$this->subject->someMethod();
}
}

$proxy = new ProxySubject();
$proxy->someMethod();


<结果>

Result:test


<示例二>

class Printer {    //代理对象,一台打印机
public function printSth() {
echo 'I can print <br>';
}
// some more function below
// ...
}

class TextShop {    //这是一个文印处理店,只文印,卖纸,不照相
private $printer;

public function __construct(Printer $printer) {
$this->printer = $printer;
}

public function sellPaper() {    //卖纸
echo 'give you some paper <br>';
}

public function __call($method, $args) {    //将代理对象有的功能交给代理对象处理,即文印工作
if(method_exists($this->printer, $method)) {
$this->printer->$method($args);
}
}
}

class PhotoShop {    //这是一个照相店,只文印,拍照,不卖纸
private $printer;

public function __construct(Printer $printer) {
$this->printer = $printer;
}

public function takePhotos() {    //照相
echo 'take photos for you <br>';
}

public function __call($method, $args) {    //将代理对象有的功能交给代理对象处理,即文印工作
if(method_exists($this->printer, $method)) {
$this->printer->$method($args);
}
}
}

$printer = new Printer();
$textShop = new TextShop($printer);
$photoShop = new PhotoShop($printer);

$textShop->printSth();
$textShop->sellPaper();
$photoShop->printSth();
$photoShop->takePhotos();


  文印处理店和照相店都具有文印的功能,所以我们可以将文印的功能代理给一台打印机,这里打印机只有一个功能,假如打印机还有n个功能,我们使用__call()方法就能够省去很多重复的代码了假如是使用继承,这样语境上就不合理,一个店显然不应该继承一台打印机而使用接口,因为我们的功能实现都是一样,也没有必要去重新实现接口的功能,所以此处使用代理,或者我们说是组合,是最佳选择。

上例中调试存在一个问题,就是$args是一个数组,需要将数组遍历出来如下改动

class Printer {    //代理对象,一台打印机
public function printSth($a) {
echo $a.'<br> I can print <br>';
}
}
class TextShop {    //这是一个文印处理店,只文印,卖纸,不照相
private $printer;
public function __construct(Printer $printer) {
$this->printer = $printer;
}
public function sellPaper() {    //卖纸
echo 'give you some paper <br>';
}
public function __call($method, $args) {    //将代理对象有的功能交给代理对象处理,即文印工作
//return call_user_func_array(array($this->printer,$method),$args);
if(method_exists($this->printer, $method)) {
foreach($args as $arg){
$this->printer->$method($arg);
}
}
}
}
class PhotoShop {    //这是一个照相店,只文印,拍照,不卖纸
private $printer;

public function __construct(Printer $printer) {
$this->printer = $printer;
}

public function takePhotos() {    //照相
echo 'take photos for you <br>';
}

public function __call($method, $args) {    //将代理对象有的功能交给代理对象处理,即文印工作
//return call_user_func_array(array($this->printer,$method),$args);
if(method_exists($this->printer, $method)) {
foreach($args as $arg){//添加遍历
$this->printer->$method($arg);
}
}
}
}
$printer = new Printer();
$textShop = new TextShop($printer);
$photoShop = new PhotoShop($printer);

$textShop->printSth(1);
$textShop->sellPaper();
$photoShop->printSth(2);
$photoShop->takePhotos();


<结果>

1
I can print
give you some paper
2
I can print
take photos for you
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: