📄 pat4g.htm
字号:
<SCRIPT>
function setFocus() {
if ((navigator.appName != "Netscape") && (parseFloat(navigator.appVersion) == 2)) {
return;
} else {
self.focus();
}
}
</SCRIPT><HTML><HEAD><TITLE>Proxy</TITLE></HEAD><BODY BGCOLOR = #FFFFFF TEXT = #000000
onLoad="setFocus()";><A NAME="top"></A><A NAME="Proxy"></A><A NAME="intent"></A><H2><A HREF="#alsoknownas"><IMG SRC="gifsb/down3.gif" BORDER=0 ALT="next: Also Known As"></A> Intent</H2> <A NAME="auto1000"></A><P>Provide a surrogate or placeholder for another object to controlaccess to it.</P><A NAME="alsoknownas"></A><H2><A HREF="#motivation"><IMG SRC="gifsb/down3.gif" BORDER=0 ALT="next: Motivation"></A> Also Known As</H2> <A NAME="auto1001"></A><P>Surrogate</P><A NAME="motivation"></A><H2><A HREF="#applicability"><IMG SRC="gifsb/down3.gif" BORDER=0 ALT="next: Applicability"></A> Motivation</H2> <A NAME="auto1002"></A><P>One reason for controlling access to an object is to defer the fullcost of its creation and initialization until we actually need to useit. Consider a document editor that can embed graphical objects in adocument. Some graphical objects, like large raster images, can beexpensive to create. But opening a document should be fast, so weshould avoid creating all the expensive objects at once when thedocument is opened. This isn't necessary anyway, because not all ofthese objects will be visible in the document at the same time.</P><A NAME="auto1003"></A><P>These constraints would suggest creating each expensive object <EM>on demand</EM>,which in this case occurs when an image becomes visible. But what dowe put in the document in place of the image? And how can we hide thefact that the image is created on demand so that we don't complicatethe editor's implementation? This optimization shouldn't impact therendering and formatting code, for example.</P><A NAME="def-proxy"></A><P>The solution is to use another object, an image <STRONG>proxy</STRONG>,that acts as a stand-in for the real image. The proxy acts just likethe image and takes care of instantiating it when it's required.</P><P ALIGN=CENTER><IMG SRC="Pictures/proxy016.gif"></P><A NAME="auto1004"></A><P>The image proxy creates the real image only when the document editorasks it to display itself by invoking its Draw operation. The proxyforwards subsequent requests directly to the image. It must thereforekeep a reference to the image after creating it.</P><A NAME="auto1005"></A><P>Let's assume that images are stored in separate files. In this case wecan use the file name as the reference to the real object. The proxyalso stores its <STRONG>extent</STRONG>, that is, its width and height.The extent lets the proxy respond to requests for its size from theformatter without actually instantiating the image.</P><A NAME="auto1006"></A><P>The following class diagram illustrates this example in more detail.</P><P ALIGN=CENTER><IMG SRC="Pictures/proxy-eg.gif"></P><A NAME="auto1007"></A><P>The document editor accesses embedded images through the interfacedefined by the abstract Graphic class. ImageProxy is a class forimages that are created on demand. ImageProxy maintains the file nameas a reference to the image on disk. The file name is passed as anargument to the ImageProxy constructor.</P><A NAME="auto1008"></A><P>ImageProxy also stores the bounding box of the image and a referenceto the real Image instance. This reference won't be valid until theproxy instantiates the real image. The Draw operation makes sure theimage is instantiated before forwarding it the request. GetExtentforwards the request to the image only if it's instantiated; otherwiseImageProxy returns the extent it stores.</P><A NAME="applicability"></A><H2><A HREF="#structure"><IMG SRC="gifsb/down3.gif" BORDER=0 ALT="next: Structure"></A> Applicability</H2> <A NAME="auto1009"></A><P>Proxy is applicable whenever there is a need for a more versatileor sophisticated reference to an object than a simple pointer. Hereare several common situations in which the Proxy pattern isapplicable:</P><OL><A NAME="idiom"></A><A NAME="remoteproxy"></A><LI>A <STRONG>remote proxy</STRONG> provides a local representativefor an object in a different address space. NEXTSTEP [<A HREF="bibfs.htm#NeXT_AppKit" TARGET="_mainDisplayFrame">Add94</A>] uses the class NXProxy forthis purpose. Coplien [<A HREF="bibfs.htm#coplien_idioms" TARGET="_mainDisplayFrame">Cop92</A>]calls this kind of proxy an "Ambassador."</LI><A NAME="auto1010"></A><P></P><A NAME="virtualproxy"></A><LI>A <STRONG>virtual proxy</STRONG>creates expensive objects on demand. The ImageProxy described in theMotivation is an example of such a proxy.</LI><A NAME="auto1011"></A><P></P><A NAME="protectionproxy"></A><LI>A <STRONG>protection proxy</STRONG>controls access to the original object. Protection proxies are usefulwhen objects should have different access rights. For example,KernelProxies in the Choices operating system [<A HREF="bibfs.htm#choices_cacm" TARGET="_mainDisplayFrame">CIRM93</A>]provide protected access to operating system objects.</LI><A NAME="auto1012"></A><P></P><A NAME="def-smartref"></A><LI>A <STRONG>smart reference</STRONG>is a replacement for a bare pointer that performs additional actionswhen an object is accessed. Typical uses include</LI><P></P><UL><A NAME="def-smartpointer"></A><LI>counting the number of references to the real object so that it can befreed automatically when there are no more references (also called<STRONG>smart pointers</STRONG> [<A HREF="bibfs.htm#SmartPointers_edelson" TARGET="_mainDisplayFrame">Ede92</A>]).</LI><A NAME="auto1013"></A><P></P><A NAME="persistence"></A><LI>loading a persistent object into memory when it's first referenced.</LI><A NAME="auto1014"></A><P></P><A NAME="auto1015"></A><LI>checking that the real object is locked before it's accessed to ensurethat no other object can change it.</LI></UL></OL><A NAME="structure"></A><H2><A HREF="#participants"><IMG SRC="gifsb/down3.gif" BORDER=0 ALT="next: Participants"></A> Structure</H2> <P ALIGN=CENTER><IMG SRC="Pictures/proxy017.gif"></P><A NAME="auto1016"></A><P>Here's a possible object diagram of a proxy structure at run-time:</P><P ALIGN=CENTER><IMG SRC="Pictures/proxy015.gif"></P><A NAME="participants"></A><H2><A HREF="#collaborations"><IMG SRC="gifsb/down3.gif" BORDER=0 ALT="next: Collaborations"></A> Participants</H2><UL><A NAME="auto1017"></A><LI><B>Proxy</B> (ImageProxy)</LI><A NAME="auto1018"></A><P></P><UL> <A NAME="auto1019"></A><LI>maintains a reference that lets the proxy access the real subject. Proxy may refer to a Subject if the RealSubject and Subject interfaces are the same.</LI> <A NAME="auto1020"></A><P><!-- extra space --></P> <A NAME="auto1021"></A><LI>provides an interface identical to Subject's so that a proxy can by substituted for the real subject.</LI> <A NAME="auto1022"></A><P><!-- extra space --></P> <A NAME="auto1023"></A><LI>controls access to the real subject and may be responsible for creating and deleting it.</LI> <A NAME="auto1024"></A><P><!-- extra space --></P> <A NAME="auto1025"></A><LI>other responsibilities depend on the kind of proxy:</LI> <A NAME="auto1026"></A><P><!-- extra space --></P> <UL> <A NAME="remoteproxy2"></A><LI><EM>remote proxies</EM> are responsible for encoding a request and its arguments and for sending the encoded request to the real subject in a different address space.</LI> <A NAME="auto1027"></A><P><!-- extra space --></P> <A NAME="virtualproxy2"></A><LI><EM>virtual proxies</EM> may cache additional information about the real subject so that they can postpone accessing it. For example, the ImageProxy from the Motivation caches the real image's extent.</LI> <A NAME="auto1028"></A><P><!-- extra space --></P> <A NAME="protectionproxy2"></A><LI><EM>protection proxies</EM> check that the caller has the access permissions required to perform a request.</LI> </UL></UL><A NAME="auto1029"></A><P></P><A NAME="subj-part-proxy"></A><LI><B>Subject</B> (Graphic)<A NAME="auto1030"></A><P></P><UL> <A NAME="auto1031"></A><LI>defines the common interface for RealSubject and Proxy so that a Proxy can be used anywhere a RealSubject is expected.</LI></UL><A NAME="auto1032"></A><P></P><A NAME="realsubj-part-proxy"></A><LI><B>RealSubject</B> (Image)<A NAME="auto1033"></A><P></P><UL> <A NAME="auto1034"></A><LI>defines the real object that the proxy represents.</LI></UL></UL><A NAME="collaborations"></A><H2><A HREF="#consequences"><IMG SRC="gifsb/down3.gif" BORDER=0 ALT="next: Consequences"></A> Collaborations</H2><UL><A NAME="auto1035"></A><LI>Proxy forwards requests to RealSubject when appropriate,depending on the kind of proxy.</LI></UL><A NAME="consequences"></A><H2><A HREF="#implementation"><IMG SRC="gifsb/down3.gif" BORDER=0 ALT="next: Implementation"></A> Consequences</H2> <A NAME="auto1036"></A><P>The Proxy pattern introduces a level of indirection when accessing anobject. The additional indirection has many uses, depending on thekind of proxy:</P><OL><A NAME="auto1037"></A><LI>A remote proxy can hide the fact that an object resides in adifferent address space.</LI><A NAME="auto1038"></A><P></P><A NAME="auto1039"></A><LI>A virtual proxy can perform optimizations such as creating anobject on demand.</LI><A NAME="auto1040"></A><P></P><A NAME="auto1041"></A><LI>Both protection proxies and smart references allow additionalhousekeeping tasks when an object is accessed.</LI></OL><A NAME="auto1042"></A><P>There's another optimization that the Proxy pattern can hide from theclient. It's called <STRONG>copy-on-write</STRONG>, and it's related tocreation on demand. Copying a large and complicated object can be anexpensive operation. If the copy is never modified, then there's noneed to incur this cost. By using a proxy to postpone the copyingprocess, we ensure that we pay the price of copying the object only ifit's modified.</P><A NAME="reference-counting"></A><P>To make copy-on-write work, the subject must be reference counted.Copying the proxy will do nothing more than increment this referencecount. Only when the client requests an operation that modifies thesubject does the proxy actually copy it. In that case the proxy mustalso decrement the subject's reference count. When the referencecount goes to zero, the subject gets deleted.</P><A NAME="auto1043"></A><P>Copy-on-write can reduce the cost of copying heavyweight subjectssignificantly.</P><A NAME="implementation"></A><H2><A HREF="#samplecode"><IMG SRC="gifsb/down3.gif" BORDER=0 ALT="next: Sample Code"></A> Implementation</H2> <A NAME="auto1044"></A><P>The Proxy pattern can exploit the following language features:</P><OL><A NAME="auto1045"></A><LI><EM>Overloading the member access operator in C++.</EM>C++ supports overloading <CODE>operator-></CODE>, the member accessoperator. Overloading this operator lets you perform additional workwhenever an object is dereferenced. This can be helpful forimplementing some kinds of proxy; the proxy behaves just like apointer.<A NAME="auto1046"></A><P>The following example illustrates how to use this technique toimplement a virtual proxy called <CODE>ImagePtr</CODE>.</P><A NAME="auto1047"></A><PRE> class Image; extern Image* LoadAnImageFile(const char*); // external function class ImagePtr { public: ImagePtr(const char* imageFile); virtual ~ImagePtr(); virtual Image* operator->(); virtual Image& operator*(); private: Image* LoadImage(); private: Image* _image; const char* _imageFile; }; ImagePtr::ImagePtr (const char* theImageFile) { _imageFile = theImageFile; _image = 0; } Image* ImagePtr::LoadImage () { if (_image == 0) { _image = LoadAnImageFile(_imageFile); } return _image; }</PRE><A NAME="auto1048"></A><P>The overloaded <CODE>-></CODE> and <CODE>*</CODE> operators use<CODE>LoadImage</CODE> to return <CODE>_image</CODE> to callers (loading itif necessary).</P><A NAME="auto1049"></A><PRE> Image* ImagePtr::operator-> () { return LoadImage(); } Image& ImagePtr::operator* () { return *LoadImage(); }</PRE><A NAME="auto1050"></A><P>This approach lets you call <CODE>Image</CODE> operations through<CODE>ImagePtr</CODE> objects without going to the trouble of making theoperations part of the<CODE>ImagePtr</CODE> interface:</P>
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -