设计模式(十三): Proxy代理模式 -- 结构型模式
设计模式(十一)代理模式Proxy(结构型)
1.概述
因为某个对象消耗太多资源,而且你的代码并不是每个逻辑路径都需要此对象, 你曾有过延迟创建对象的想法吗 ( if和else就是不同的两条逻辑路径) ? 你有想过限制访问某个对象,也就是说,提供一组方法给普通用户,特别方法给管理员用户?以上两种需求都非常类似,并且都需要解决一个更大的问题:你如何提供一致的接口给某个对象让它可以改变其内部功能,或者是从来不存在的功能? 可以通过引入一个新的对象,来实现对真实对象的操作或者将新的对象作为真实对象的一个替身。即代理对象。它可以在客户端和目标对象之间起到中介的作用,并且可以通过代理对象去掉客户不能看到的内容和服务或者添加客户需要的额外服务。
例子1:经典例子就是网络代理,你想访问facebook或者twitter ,如何绕过GFW,找个代理网站。
例子2:可以调用远程代理处理一些操作如图:
2.问题:
你怎样才能在不直接操作对象的情况下,对此对象进行访问?
3.解决方案
代理模式:为其他对象提供一种代理,并以控制对这个对象的访问。(Provide asurrogate or placeholderforanother 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[0]->low->attributes());
- $high = $weatherxml->weather->forecast_conditions[0]->high->attributes();
- $icon= 'http://www.google.com'. $weatherxml->weather->forecast_conditions[0]->icon->attributes();
- $condition=$weatherxml->weather->forecast_conditions[0]->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并不一定要求保持接口的一致性,只要能够实现间接控制,有时候损及一些透明性是可以接受的。例如上
设计模式(十三): Proxy代理模式 -- 结构型模式的更多相关文章
- 代理模式/proxy模式/结构型模式
代理模式proxy 定义 为其他对象提供一种代理,并以控制对这个对象的访问.最简单的理解,买东西都是要去商店的,不会去工厂. java实现三要素 proxy(代理)+subject(接口)+realS ...
- .NET设计模式(15):结构型模式专题总结(转)
摘要:结构型模式,顾名思义讨论的是类和对象的结构,它采用继承机制来组合接口或实现(类结构型模式),或者通过组合一些对象,从而实现新的功能(对象结构型模式).这些结构型模式,它们在某些方面具有很大的相似 ...
- 设计模式(十二): Flyweight享元模式 -- 结构型模式
说明: 相对于其它模式,Flyweight模式在PHP实现似乎没有太大的意义,因为PHP的生命周期就在一个请求,请求执行完了,php占用的资源都被释放.我们只是为了学习而简单做了介绍. 1. 概述 面 ...
- 设计模式(十):Decorator装饰者模式 -- 结构型模式
1. 概述 若你从事过面向对象开发,实现给一个类或对象增加行为,使用继承机制,这是所有面向对象语言的一个基本特性.如果已经存在的一个类缺少某些方法,或者须要给方法添加更多的功能(魅力),你也许会仅仅继 ...
- 设计模式学习之路——Facade 外观模式(结构型模式)
动机: 组件的客户和组件中各种复杂的子系统有了过多的耦合,随着外部客户程序和各子系统的演化,这种过多的耦合面临很多变化的挑战.如何简化外部客户程序和系统间的交互接口?如何将外部客户程序的演化和内部子系 ...
- 设计模式(十一):FACADE外观模式 -- 结构型模式
1. 概述 外观模式,我们通过外观的包装,使应用程序只能看到外观对象,而不会看到具体的细节对象,这样无疑会降低应用程序的复杂度,并且提高了程序的可维护性.例子1:一个电源总开关可以控制四盏灯.一个风扇 ...
- 设计模式(八):Bridge桥接模式 -- 结构型模式
1. 概述 在软件系统中,某些类型由于自身的逻辑,它具有两个或多个维度的变化,那么如何应对这种“多维度的变化”?如何利用面向对象的技术来使得该类型能够轻松的沿着多个方向进行变化,而又不引入额外的复杂度 ...
- Proxy代理模式(结构型模式)
1.问题 在面向对象系统中,有些对象由于某种原因(比如创建对象的开销很大,或者某些操作需要安全控制,或者需要进程外的访问等),直接访问会给调用者带来麻烦,那么如何在不损失接口透明性的情况下,解决这些麻 ...
- 设计模式(九):Composite组合模式 -- 结构型模式
1. 概述 在数据结构里面,树结构是很重要,我们可以把树的结构应用到设计模式里面. 例子1:就是多级树形菜单. 例子2:文件和文件夹目录 2.问题 我们可以使用简单的对象组合成复杂的对象,而这个复杂对 ...
随机推荐
- Demon_打砖块(建造一面墙,发射子弹打砖块)
using UnityEngine; using System.Collections; public class CubeInit : MonoBehaviour { //砖块预设体 public ...
- 当多个客户请求一个servlet时,引擎为每个客户启动一个线程,那么servlet类的成员变量被所有的线程共享?
因为servlet的实现是单例,多线程也就是说,N个客户端请求同一个servlet,他们所请求的是同一个对象,成员变量是属于这个对象的,因此成员变量也被共享了因此在servlet编程中,无状态的ser ...
- Android 从清单配置文件元数据中获取值
最近在上班工作当中,也尝到了一些新的知识,现总结如下(1)从AndroidManifest.xml配置文件中获取meta数据 // 从Manifest.xml配置文件中获取数据 public stat ...
- JavaScripts学习日记——XML DTD Schema
今日关键词: XML DTD Schema 1.XML 1 XML的概述 1.1 什么是XML XML全称为Extensible Markup Language,意思是可扩展的标记语言.XML语法上和 ...
- 【网络流#6】POJ 3041 Asteroids 二分图最大匹配 - 《挑战程序设计竞赛》例题
学习网络流中ing...作为初学者练习是不可少的~~~构图方法因为书上很详细了,所以就简单说一说 把光束作为图的顶点,小行星当做连接顶点的边,建图,由于 最小顶点覆盖 等于 二分图最大匹配 ,因此求二 ...
- 使用linux操作系统的公司服务器有哪些品牌
服务器硬件是什么牌子的? 操心系统有哪些?cpu是哪些?
- 【转】三十分钟学会STL算法
转载自: http://net.pku.edu.cn/~yhf/UsingSTL.htm 这是本小人书.原名是<using stl>,不知道是谁写的.不过我倒觉得很有趣,所以化了两个晚上把 ...
- [译]一个灵活的 Trello 敏捷工作流
[译]一个灵活的 Trello 敏捷工作流 翻译自 An Agile Trello Workflow That Keeps Tasks Flexible Getting things done 可不只 ...
- Lesson 5: Typography in Product Design
Lesson 5: Typography in Product Design Article 1: Interactive Guide to Blog Typography 布局(Layout) 用空 ...
- vim 学习笔记
vim介绍:一款编辑器,另外一般linux系统会自带,所以一般linux下日志.配置文件等 纯文本文件的修改编辑等通过vim操作 学会的好处:1 方便操作linux下日志.配置文件等纯文本文件 2 功 ...