وکیل، در کلیترین حالت، کلاس واسطهای برای انجام کار دیگری است. پروکسی میتواند رابط هر چیزی باشد: یک ارتباطه تحت شبکه، شیء بزرگی در داخل حافظه، یک فایل، یا یک سری از منابع دیگر که نمونهسازی از آنها بسیار سخت یا غیرممکن است. به صورت خلاصه، وکیل پوشهبند یا نیروی اجراییای است که توسط مشتری صدا زده میشود تا به شیء اصلی در پشتپرده دسترسی پیدا کند. استفاده از وکیل میتواند انتقال به شی واقعی را راحتتر کند یا روشهای دیگری برای آن به وجود بیاورد. در الگوی وکالت قابلیتهای اضافهتر میتواند به وجود بیاید، بهطور مثال، استفاده از حافظه موقت، برای وقتی که استفاده از شیء اصلی هزینه پردازشی و هزینه دسترسی به حافظه زیادی داشته باشد، یا در چک کردن شرایط اولیه قبل از آن که عملیات بر روی شیء اصلی اعمال شود. برای مشتری با استفاده از وکیل مانند استفاده از شیء اصلی است، چرا که رابط هر دو مشابه است.
سناریوهای احتمالی استفاده
وکالت از راه دور
در ارتباطات اشیاء توزیع شده، از یک شیء محلی به عنوان نمایشدهنده شیء خارجی (که متعلق به یک فضای خارجی از آدرسدهیها است) است. شیء محلی به عنوان وکیل شیء خارجی شناخته میشود، و اجرای توابع شیء محلی به اجرای توابع در شیء اصلی میانجامد. به عنوان مثال: دستگاه خودپرداز، که در آن یک وکیل از اطلاعات بانکی در سرور خارجی وجود دارد.
وکالت مجازی
در مواجهه به شیء پیچیده یا سنگین وزن (از نظر حافظه)، در بعضی موارد نشان دادن تنها بدنهای از شیء میتواند مفیدتر باشد. وقتی که تصویر ایجاد شده اندازه بزرگی داشته باشد، میتواند توسط یک وکیل مجازی، که بر روی شیء واقعی پیادهسازی شده، نشان داده شود.
وکالت امنیتی
برای محافظت از کنترل دسترسیها میتوان این وظیفه را به یک وکیل سپرد.
مثال
#C
interfaceICar{voidDriveCar();}// Real ObjectpublicclassCar:ICar{publicvoidDriveCar(){Console.WriteLine("Car has been driven!");}}//Proxy ObjectpublicclassProxyCar:ICar{privateDriverdriver;privateICarrealCar;publicProxyCar(Driverdriver){this.driver=driver;this.realCar=newCar();}publicvoidDriveCar(){if(driver.Age<=16)Console.WriteLine("Sorry, the driver is too young to drive.");elsethis.realCar.DriveCar();}}publicclassDriver{privateintAge{get;set;}publicDriver(intage){this.Age=age;}}// How to use above Proxy class?privatevoidbtnProxy_Click(objectsender,EventArgse){ICarcar=newProxyCar(newDriver(16));car.DriveCar();car=newProxyCar(newDriver(25));car.DriveCar();}
خروجی
Sorry, the driver is too young to drive.
Car has been driven!
یادداشت:
وکیل ممکن است اطلاعاتی از شیء حقیقی را از کاربر مخفی کند.
پروکسی ممکن است بهینهسازیهایی انجام دهد. بهطور مثال فراخوانی تنها در هنگام نیاز.
وکیل ممکن است کارهای اضافهتری در قبال شیء اصلی انجام دهد، مثل انجام حسابرسیها.
الگوی وکالت با عنوان الگوی جانشینی نیز شناخته میشود.
++C
classICar{public:virtualvoidDriveCar()=0;};classCar:publicICar{voidDriveCar()override{std::cout<<"Car has been driven!";}};classProxyCar:publicICar{private:ICar*realCar=newCar();int_driver_age;public:ProxyCar(constintdriver_age):_driver_age(driver_age){}voidDriveCar(){if(_driver_age>16)realCar->DriveCar();elsestd::cout<<"Sorry, the driver is too young to drive.";}};// How to use above Proxy class?voidmain(){ICar*car=newProxyCar(16);car->DriveCar();deletecar;car=newProxyCar(25);car->DriveCar();deletecar;}
کریستال
abstractclassAbstractCarabstractdefdriveendclassCar<AbstractCardefdriveputs"Car has been driven!"endendclassDrivergetterage:Int32definitialize(@age)endendclassProxyCar<AbstractCarprivategetterdriver:Driverprivategetterreal_car:AbstractCardefinitialize(@driver)@real_car=Car.newenddefdriveifdriver.age<=16puts"Sorry, the driver is too young to drive."else@real_car.driveendendend# Programdriver=Driver.new(16)car=ProxyCar.new(driver)car.drivedriver=Driver.new(25)car=ProxyCar.new(driver)car.drive
خروجی
Sorry, the driver is too young to drive.
Car has been driven!
Delphi / Object Pascal
// Proxy Design patternunitDesignPattern.Proxy;interfacetype// Car InterfaceICar=interfaceprocedureDriveCar;end;// TCar class, implementing ICarTCar=Class(TInterfacedObject,ICar)classfunctionNew:ICar;procedureDriveCar;End;// Driver InterfaceIDriver=interfacefunctionAge:Integer;end;// TDriver Class, implementing IDriverTDriver=Class(TInterfacedObject,IDriver)privateFAge:Integer;publicconstructorCreate(Age:Integer);Overload;classfunctionNew(Age:Integer):IDriver;functionAge:Integer;End;// Proxy ObjectTProxyCar=Class(TInterfacedObject,ICar)privateFDriver:IDriver;FRealCar:ICar;publicconstructorCreate(Driver:IDriver);Overload;classfunctionNew(Driver:IDriver):ICar;procedureDriveCar;End;implementation{ TCar Implementation }classfunctionTCar.New:ICar;beginResult:=Create;end;procedureTCar.DriveCar;beginWriteLn('Car has been driven!');end;{ TDriver Implementation }constructorTDriver.Create(Age:Integer);begininheritedCreate;FAge:=Age;end;classfunctionTDriver.New(Age:Integer):IDriver;beginResult:=Create(Age);end;functionTDriver.Age:Integer;beginResult:=FAge;end;{ TProxyCar Implementation }constructorTProxyCar.Create(Driver:IDriver);begininheritedCreate;Self.FDriver:=Driver;Self.FRealCar:=TCar.CreateASICar;end;classfunctionTProxyCar.New(Driver:IDriver):ICar;beginResult:=Create(Driver);end;procedureTProxyCar.DriveCar;beginif(FDriver.Age<=16)thenWriteLn('Sorry, the driver is too young to drive.')elseFRealCar.DriveCar();end;end.
استفاده
program Project1;
{$APPTYPE Console}
uses
DesignPattern.Proxy in 'DesignPattern.Proxy.pas';
begin
TProxyCar.New(TDriver.New(16)).DriveCar;
TProxyCar.New(TDriver.New(25)).DriveCar;
end.
جاوا
این کد Java یک نمونه از «وکالت مجازی» را به نمایش میگذارد. کلاس ProxyImage برای دسترسی به کنترل از راه دور استفاده میشود.
مثال به جای آن که ابتدا کلاس را بسازد ابتدا یک رابط به نام displayImage ساخته است که توسط تمامی کلاسهایی که آن را پیاده میکنند نوشته میشود.
کلاس وکالت ProxyImage بر روی سامانه دیگری اجرا میشود و تصویر اصلی RealImage را در آنجا نمایش میدهد. اطلاعات تصویر از روی حافظه دسترسی پیدا میکنند. با استفاده از الگوی وکالت، کد ProxyImage جلوی دسترسیهای متعدد به تصویر را میگیرد و دسترسی به آن از سامانه دیگر موجب بهینه سازی در استفاده از حافظه خواهد بود. لازم به ذکر است که هرچند فراخوانی کاهلانهای که در این مثال نمایش داده شده جزو الگوی وکالت اصلی نیست، در حقیقت یک ویژگی پیشرفتهتر است که توسط الگوی وکالت امکانپذیر شدهاست.
interfaceImage{publicvoiddisplayImage();}// On System AclassRealImageimplementsImage{privateStringfilename=null;/** * Constructor * @param filename */publicRealImage(finalStringfilename){this.filename=filename;loadImageFromDisk();}/** * Loads the image from the disk */privatevoidloadImageFromDisk(){System.out.println("Loading "+filename);}/** * Displays the image */publicvoiddisplayImage(){System.out.println("Displaying "+filename);}}// On System BclassProxyImageimplementsImage{privateRealImageimage=null;privateStringfilename=null;/** * Constructor * @param filename */publicProxyImage(finalStringfilename){this.filename=filename;}/** * Displays the image */publicvoiddisplayImage(){if(image==null){image=newRealImage(filename);}image.displayImage();}}classProxyExample{/** * Test method */publicstaticvoidmain(finalString[]arguments){finalImageimage1=newProxyImage("HiRes_10MB_Photo1");finalImageimage2=newProxyImage("HiRes_10MB_Photo2");image1.displayImage();// loading necessaryimage1.displayImage();// loading unnecessaryimage2.displayImage();// loading necessaryimage2.displayImage();// loading unnecessaryimage1.displayImage();// loading unnecessary}}