1.概述

因为某个对象消耗太多资源,而且你的代码并不是每个逻辑路径都需要此对象, 你曾有过延迟创建对象的想法吗 ( if和else就是不同的两条逻辑路径) ? 你有想过限制访问某个对象,也就是说,提供一组方法给普通用户,特别方法给管理员用户?以上两种需求都非常类似,并且都需要解决一个更大的问题:你如何提 供一致的接口给某个对象让它可以改变其内部功能,或者是从来不存在的功能? 可以通过引入一个新的对象,来实现对真实对象的操作或者将新的对象作为真实对象的一个替身。即代理对象。它可以在客户端和目标对象之间起到中介的作用,并且可以通过代理对象去掉客户不能看到的内容和服务或者添加客户需要的额外服务

例子1:经典例子就是网络代理,你想访问facebook或者twitter ,如何绕过GFW,找个代理网站。

例子2:可以调用远程代理处理一些操作如图:

2.问题:

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

3.解决方案

代理模式:为其他对象提供一种代理,并以控制对这个对象的访问。(Provide asurrogate or placeholder foranother object tocontrol access to it. )而对一个对象进行访问控制的一个原因是为了只有在我们确实需要这个对象时才对它进行创建和初始化。它是给某一个对象提供一个替代者(占位者),使之在client对象和subject对象之间编码更有效率。代理可以提供延迟实例化(lazy instantiation),控制访问, 等等,包括只在调用中传递。 一个处理纯本地资源的代理有时被称作虚拟代理。远程服务的代理常常称为远程代理。强制 控制访问的代理称为保护代理。

4.实用性

在需要用比较通用和复杂的对象指针代替简单的指针的时候,使用 Proxy模式。下面是一些可以使用Proxy模式常见情况:
1) 远程代理(Remote  Proxy)为一个位于不同的地址空间的对象提供一个本地的代理对象。这个不同的地址空间可以是在同一台主机中,也可是在另一台主机中,远程代理又叫做大使(Ambassador)
2) 虚拟代理(Virtual Proxy)根据需要创建开销很大的对象。如果需要创建一个资源消耗较大的对象,先创建一个消耗相对较小的对象来表示,真实对象只在需要时才会被真正创建。 
3) 保护代理(Protection Proxy)控制对原始对象的访问。保护代理用于对象应该有不同的访问权限的时候。
4) 智能指引(Smart Reference)取代了简单的指针,它在访问对象时执行一些附加操作。
5) Copy-on-Write代理:它是虚拟代理的一种,把复制(克隆)操作延迟到只有在客户端真正需要时才执行。一般来说,对象的深克隆是一个开销较大的操作,Copy-on-Write代理可以让这个操作延迟,只有对象被用到的时候才被克隆。

5. 结构

Uml图:

简单结构示意图:

6.模式的组成

1)代理角色(Proxy):
. 保存一个引用使得代理可以访问实体。若 RealSubject和Subject的接口相同,Proxy会引用Subject。
. 提供一个与Subject的接口相同的接口,这样代理就可以用来替代实体。
. 控制对实体的存取,并可能负责创建和删除它。
. 其他功能依赖于代理的类型:
• Remote Proxy负责对请求及其参数进行编码,并向不同地址空间中的实体发送已编码的请求。
• Virtual Proxy可以缓存实体的附加信息,以便延迟对它的访问。
• Protection Proxy检查调用者是否具有实现一个请求所必需的访问权限。
2) 抽象主题角色(Subject):定义真实主题角色RealSubject
和 抽象主题角色Proxy的共用接口,这样就在任何使用RealSubject的地方都可以使
用Proxy。代理主题通过持有真实主题RealSubject的引用,不但可以控制真实主题RealSubject的创建或删除,可以在真实主题RealSubject被调用前进行拦截,或在调用后进行某些操作.

3) 真实主题角色(RealSubject):定义了代理角色(proxy)所代表的具体对象.

7. 效果

Proxy模式在访问对象时引入了一定程度的间接性。根据代理的类型,附加的间接性有多种用途:
1) Remote Proxy可以隐藏一个对象存在于不同地址空间的事实。也使得客户端可以访问在远程机器上的对象,远程机器可能具有更好的计算性能与处理速度,可以快速响应并处理客户端请求。
2) Virtual Proxy 可以进行最优化,例如根据要求创建对象。即通过使用一个小对象来代表一个大对象,可以减少系统资源的消耗。
3) Protection Proxies和Smart Reference都允许在访问一个对象时有一些附加的内务处理(Housekeeping task) 。

Proxy模式还可以对用户隐藏另一种称之为写时复制(copy-on-write)的优化方式,该优化与根据需要创建对象有关。拷贝一个庞大而复杂的对象是一种开销很大的操作,如果这个拷贝根本没有被修改,那么这些开销就没有必要。用代理延迟这一拷贝过程,我们可以保证只有当这个对象被修改的时候才对它进行拷贝。在实现copy-on-write时必须对实体进行引用计数。拷贝代理仅会增加引用计数。只有当用户请求一个修改该实体的操作时,代理才会真正的拷贝它。在这种情况下,代理还必须减
少实体的引用计数。当引用的数目为零时,这个实体将被删除。copy-on-write可以大幅度的降低拷贝庞大实体时的开销。

代理模式能够协调调用者和被调用者,在一定程度上降低了系统的耦合度。

代理模式的缺点
由于在客户端和真实主题之间增加了代理对象,因此有些类型的代理模式可能会造成请求的处理速度变慢。
实现代理模式需要额外的工作,有些代理模式的实现非常复杂。

8.实现

我们用获取天气预报的例子说明代理模式:

    <?php
/**
* 代理模式
*
* 为其他对象提供一个代理以控制这个对象的访问
*
*/
/**
* 抽象主题角色(Subject):天气
*
*/
interface Weather
{
public function request($city);
public function display($city);
public function isValidCity($city); } /**
* 真实主题角色(RealSubject):
*
*/
class RealWeather implements Weather
{
protected $_url = 'http://www.google.com/ig/api?&oe=utf-8&hl=zh-cn&weather=';
protected $_weatherXml = '' ;
function __construct(){ } public function request($city){
$this->_weatherXml = file_get_contents($this->_url . $city );
}
public function display($city ){
if ($this->_weatherXml == '') {
$this->request($city);
}
//$this->_weatherXml = mb_convert_encoding($this->_weatherXml, 'UTF-8', 'GB2312');
$weatherxml = simplexml_load_string($this->_weatherXml);
$low = intval($weatherxml->weather->forecast_conditions[]->low->attributes());
$high = $weatherxml->weather->forecast_conditions[]->high->attributes();
$icon= 'http://www.google.com'. $weatherxml->weather->forecast_conditions[]->icon->attributes();
$condition=$weatherxml->weather->forecast_conditions[]->condition->attributes();
$weather = date('Y年n月j日').' 天气预报:<span class="cor_ff6c00 f_bold">'.$city_names[$city].' </span> <img class="v_middle" src="'.$icon.'" alt="'.$condition.'" width="16" height="17" align="absmiddle" /> <span class="f_bold"></span>: '.$low.'°C ~ '.$high.'°C '.$condition;
echo $weather;
} public function isValidCity($city){ } } /**
* 代理角色(Proxy):延迟代理
*
*/
class ProxyWeather implements Weather {
private $_client ;
private function client() {
if (! $this->_client instanceof RealWeather) {
$this->_client = new RealWeather();
}
return $this->_client; }
public function request($city){
$this->_client()->request($city);
} public function isValidCity($city) {
return $this->_client()->isValidCity($city);
} public function display($city) {
return $this->client()->display($city);
}
}
/**
* 代理角色(Proxy):动态代理
*
*/
class GenericProxyWeather { protected $_subject;
public function __construct($subject) {
$this->_subject = $subject;
} public function __call($method, $args) {
return call_user_func_array(
array($this->_subject, $method),
$args);
} } class Client{ static function main(){
$proxy = new ProxyWeather();
$report = $proxy->display('beijing');
}
static function Genericmain(){
$proxy = new GenericProxyWeather(new RealWeather());
$report = $proxy->display('beijing');
}
}
header('Content-type:text/html;charset=UTF-8');
Client::main();
//Client::Genericmain();

9. 与其他相关模式

1)适配器模式Adapter:适配器Adapter 为它所适配的对象提供了一个不同的接口。相反,代理提供了与它的实体相同的接口。然而,用于访问保护的代理可能会拒绝执行实体会执行的操作,因此,它的接口实际上可能只是实体接口的一个子集。

2) 装饰器模式Decorator:尽管Decorator的实现部分与代理相似,但
Decorator的目的不一样。Decorator为对象添加一个或多个功能,而代理则控制对对象的访问。

10.总结

代理模式在很多情况下都非常有用,特别是你想强行控制一个对象的时候,比如:延迟加载,监视状态变更的方法等等

1、“增加一层间接层”是软件系统中对许多负责问题的一种常见解决方法。在面向对象系统中,直接使用某些对象会带来很多问题,作为间接层的proxy对象便是解决这一问题的常用手段。

2、具体proxy设计模式的实现方法、实现粒度都相差很大,有些可能对单个对象作细粒度的控制,有些可能对组件模块提供抽象代理层,在架构层次对对象作proxy。

3、proxy并不一定要求保持接口的一致性,只要能够实现间接控制,有时候损及一些透明性是可以接受的。

本文章摘自 http://blog.csdn.net/hguisu/article/details/7542143

设计模式(十一)代理模式Proxy(结构型)的更多相关文章

  1. Java设计模式11:常用设计模式之代理模式(结构型模式)

    1. Java之代理模式(Proxy Pattern) (1)概述: 代理模式的作用是:为其他对象提供一种代理以控制对这个对象的访问. 在某些情况下,一个客户不想或者不能直接引用另一个对象,而代理对象 ...

  2. 设计模式12: Proxy 代理模式(结构型模式)

    Proxy 代理模式(结构型模式) 直接与间接 人们对于复杂的软件系统常常有一种处理手法,即增加一层间接层,从而对系统获得一种更为灵活.满足特定需求的解决方案.如下图,开始时,A需要和B进行3次通信, ...

  3. 设计模式 笔记 代理模式 Proxy

    //---------------------------15/04/21---------------------------- //Proxy 代理模式-----对象结构型模式 /* 1:意图: ...

  4. 乐在其中设计模式(C#) - 代理模式(Proxy Pattern)

    原文:乐在其中设计模式(C#) - 代理模式(Proxy Pattern) [索引页][源码下载] 乐在其中设计模式(C#) - 代理模式(Proxy Pattern) 作者:webabcd 介绍 为 ...

  5. 大熊君说说JS与设计模式之------代理模式Proxy

    一,总体概要 1,笔者浅谈 当我们浏览网页时,网页中的图片有时不会立即展示出来,这就是通过虚拟代理来替代了真实的图片,而代理存储了真实图片的路径和尺寸,这就是代理方式的一种. 代理模式是比较有用途的一 ...

  6. 二十四种设计模式:代理模式(Proxy Pattern)

    代理模式(Proxy Pattern) 介绍为其他对象提供一个代理以控制对这个对象的访问. 示例有一个Message实体类,某对象对它的操作有Insert()和Get()方法,用一个代理来控制对这个对 ...

  7. 结构型设计模式之代理模式(Proxy)

    结构 意图 为其他对象提供一种代理以控制对这个对象的访问. 适用性 在需要用比较通用和复杂的对象指针代替简单的指针的时候,使用P r o x y 模式.下面是一 些可以使用P r o x y 模式常见 ...

  8. Java基础-设计模式之-代理模式Proxy

    代理模式是对象的结构模式.代理模式给某一个对象提供一个代理对象,并由代理对象控制对原对象的引用. 代理模式是常用的Java 设计模式,它的特征是代理类与委托类有同样的接口,代理类主要负责为委托类预处理 ...

  9. [设计模式] 12 代理模式 proxy

    在GOF的<设计模式:可复用面向对象软件的基础>一书中对代理模式是这样说的:为其他对象提供一种代理以控制对这个对象的访问.结合上面的游戏代理的例子和下面的图,我们来进行分析一下.以前你是这 ...

  10. c#设计模式之代理模式(Proxy Pattern)

    引言 代理这个词语,大家在现实世界已经频繁的接触过,例如火车站代理售票点,因为这些代理售票点的存在,我们不必要去火车站的售票处就可以查询或者取到火车票.代理点本身是没有能力生产车票的,我们在代理处享受 ...

随机推荐

  1. poj2105---用指针对数组分块操作

    #include <stdio.h> #include <stdlib.h> ; int pow1(int a,int b) { ,i; ) ; ;i<b;i++) { ...

  2. Spring AOP AspectJ Pointcut 表达式例子

    主要来源:http://howtodoinjava.com/spring/spring-aop/writing-spring-aop-aspectj-pointcut-expressions-with ...

  3. 音乐ID3 中 专辑封面解析(APIC帧)

    ID3V2 中 APIC 帧标识 专辑封面.前几天 百度 谷歌 都没有找到具体的说明.有点小伤人. 最好参考  Android 中的 id3.cpp 以及一个java 开源 id3 库.找到这里的规格 ...

  4. Cocos2d-x 3.0 lua规划 真正的现在Android在响应Home密钥和Back纽带

    local listenerKey= cc.EventListenerKeyboard:create() local function onKeyReleaseed(keycode,event) if ...

  5. k8s之scheduler

    一.概述 调度器是kubernetes中独特而又重要的一个模块,独特是因为scheduler是唯一一个以plugin形式存在的组件,重要是因为kubernetes中最重要的基础单元pod的部署是通过s ...

  6. 编写可维护的JS 04

    4.变量.函数和运算符 变量 变量声明提前,单var 函数声明 先声明fn再执行 函数声明不应出现在语句块中 函数调用间隔 函数名与左括号间无间隔 立即调用函数 (fuction(){}) 严格模式  ...

  7. Tip插件的使用

    Tip.js概述——美化弹窗插件 开源美化弹窗插件1.JavaScript原生代码2.美化网站用户界面 Tip.js插件的显示效果 Tip.js的使用方法 Tip({ str:'alert上需要弹出显 ...

  8. ZOJ 1563 Pearls(动态规划)

    /* 分析: 因为他给的数据是递增的 而求得是这些数据总的 最优解 所以我们可以考虑,它的子问题求解不影响总的求解 也就是我们可以先求出 第一个的最优解 第二个....以此类推到总的最优解 那么我们想 ...

  9. c# 柱状图(转载)

    // c# 显示柱状图 using System; using System.Data; using System.Configuration; using System.Web; using Sys ...

  10. HOJ1008

    #include<iostream> using namespace std; int main(){ ; ; ){ ; ; numTemp = N; ) && count ...