Proxy模式的产生原因:
在某些情况下,一个对象不想或者不能直接引用另一个对象,而代理对象可以在客户端和目标对象之间起到中介的作用。
当由于某些特定的需要调用的对象在另外一台机器上,需要跨越网络才能访问,在没有WebService的情况下我们需要直接coding去处理网络连接、处理打包、解包等等非常复杂的步骤,而WebService的出现帮我们解决了其中的一些问题简化客户端的处理,我们只需在客户端建立一个远程对象的代理,客户端就象调用本地对象一样调用该代理,再由代理去跟实际对象联系,对于客户端来说可能根本没有感觉到调用的东西在网络另外一端。
Proxy模式的作用:
提供一个Subject角色,它定义了Proxy与ConcreteSubject的功用接口,使得任何使用ConcreteSubject的地方都能使用Proxy,Proxy对象维护了一个对ConcreteSubject对象的引用,Proxy接受来至客户端请求,通过这个引用,将请求转给具体的ConcreteSubject对象,Proxy在执行具体对象操作时可以附加其他的操作。这样通过增加代理来解耦客户端与调用对象之间的调用,封装了原来客户端调用具体对象的一些相关细节,客户端不在依赖具体的调用对象,具体对象的修改对客户端来说是透明的,不会影响客户端的修改。
Proxy模式的构成:
抽象主题(Subject)角色:声明了代理主题和具体主题的公共接口,使任何需要具体主题的地方都能用代理主题代替。
代理主题(Proxy)角色:代理对象角色内部含有对具体对象的引用,从而可以操作具体对象,同时代理对象提供与具体对象相同的接口以便在任何时刻都能代替具体对象。同时,代理对象可以在执行具体对象操作时,附加其他的操作,相当于对具体对象进行封装。
具体具体对象(ConcreteSubject)角色:代理角色所代表的具体对象,是我们最终要引用的对象。
Proxy模式典型的结构图如图1所示:
Proxy模式的示例程序:
Proxy.h
#ifndef _PROXY_H_ #define _PROXY_H_ // 定义了Proxy和ConcreteSubject的公有接口, // 这样就可以在任何需要使用到ConcreteSubject的地方都使用Proxy. class Subject { public: virtual ~Subject(); virtual void Request()=0; protected: Subject(); }; class ConcreteSubject : public Subject { public: ConcreteSubject(); ~ConcreteSubject(); virtual void Request(); }; //定义代理类 class Proxy : public Subject { public: Proxy(); ~Proxy(); void DoSomething1(); virtual void Request(); void DoSomething2(); private: Subject* _subject; }; #endif
Proxy.cpp
#include "Proxy.h" #include "iostream" using namespace std; Subject::Subject() {} Subject::~Subject() {} ConcreteSubject::ConcreteSubject() {} ConcreteSubject::~ConcreteSubject() {} void ConcreteSubject::Request() { cout << "ConcreteSubject::Request" << endl; } Proxy::Proxy() : _subject(NULL) {} Proxy::~Proxy() {} void Proxy::DoSomething1() { cout << "Proxy::DoSomething1" << endl; } void Proxy::DoSomething2() { cout << "Proxy::DoSomething2" << endl; } void Proxy::Request() { if(NULL == this->_subject) { this->_subject = new ConcreteSubject(); } this->DoSomething1();//表示额外附加的操作 this->_subject->Request();//代理的实体类操作 this->DoSomething2();//表示额外附加的操作 }
Main.cpp
#include "Proxy.h" int main() { Proxy* proxy = new Proxy(); proxy->Request(); return 0; }
Proxy模式使用场景:
(1).创建开销大的对象时候,比如显示一幅大的图片,我们将这个创建的过程交给代理去完成,GoF称之为虚代理(Virtual Proxy)。
(2).为网络上的对象创建一个局部的本地代理,比如要操作一个网络上的一个对象(网络性能不好的时候,问题尤其突出),我们将这个操纵的过程交给一个代理去完成,GoF称之为远程代理(Remote Proxy)。
(3).对对象进行控制访问的时候,比如在Jive论坛中不同权限的用户(如管理员、普通用户等)将获得不同层次的操作权限,我们将这个工作交给一个代理去完成,GoF称之为保护代理(Protection Proxy)。
(4).当一个对象被引用时,提供一些额外的操作,比如将对此对象调用的次数记录下来等。是指当调用真实的对象时,代理处理另外一些事。如计算真实对象的引用次数,这样当该对象没有引用时,可以自动释放它;或当第一次引用一个持久对象时,将它装入内存;或在访问一个实际对象前,检查是否已经锁定它,以确保其他对象不能改变它。它们都是通过代理在访问一个对象时附加一些内务处理。又称智能引用(Smart Reference)代理。
在所有种类的代理模式中,虚拟(Virtual)代理、远程(Remote)代理、智能引用代理(Smart Reference Proxy)和保护(Protect or Access)代理是最为常见的代理模式。
Proxy代理模式与外观模式的区别:
(1).外观模式也是屏蔽复杂性的,但是外观模式不会实现客户端调用的目标类型接口。
(2).一般客户端调用外观模式的方法都是直接调用。
(3).代理模式中对客户端目标对象类型抽象接口具体化了。
(4).外观模式是代理模式中一种特殊的子级模式(广泛的,非约束性)。
Proxy代理模式使用总结:
Proxy代理模式非常常用,大致的思想就是通过为对象加一个代理来降低对象的使用复杂度、或是提升对象使用的友好度、或是提高对象使用的效率。
GoF《设计模式》中说的:为其他对象提供一种代理以控制这个对象的访问。理类型从某种角度上讲也可以起到控制被代理类型的访问的作用。