الگوی وکالت

پروکسی در UML
پروکسی در LePUS3 (افسانه)

الگوی وکالت در برنامه‌نویسی، از جمله الگوهای طراحی نرم‌افزار است.

وکیل، در کلی‌ترین حالت، کلاس واسطه‌ای برای انجام کار دیگری است. پروکسی می‌تواند رابط هر چیزی باشد: یک ارتباطه تحت شبکه، شیء بزرگی در داخل حافظه، یک فایل، یا یک سری از منابع دیگر که نمونه‌سازی از آن‌ها بسیار سخت یا غیرممکن است. به صورت خلاصه، وکیل پوشه‌بند یا نیروی اجرایی‌ای است که توسط مشتری صدا زده می‌شود تا به شیء اصلی در پشت‌پرده دسترسی پیدا کند. استفاده از وکیل می‌تواند انتقال به شی واقعی را راحت‌تر کند یا روش‌های دیگری برای آن به وجود بیاورد. در الگوی وکالت قابلیت‌های اضافه‌تر می‌تواند به وجود بیاید، به‌طور مثال، استفاده از حافظه موقت، برای وقتی که استفاده از شیء اصلی هزینه پردازشی و هزینه دسترسی به حافظه زیادی داشته باشد، یا در چک کردن شرایط اولیه قبل از آن که عملیات بر روی شیء اصلی اعمال شود. برای مشتری با استفاده از وکیل مانند استفاده از شیء اصلی است، چرا که رابط هر دو مشابه است.

سناریوهای احتمالی استفاده

وکالت از راه دور

در ارتباطات اشیاء توزیع شده، از یک شیء محلی به عنوان نمایش‌دهنده شیء خارجی (که متعلق به یک فضای خارجی از آدرس‌دهی‌ها است) است. شیء محلی به عنوان وکیل شیء خارجی شناخته می‌شود، و اجرای توابع شیء محلی به اجرای توابع در شیء اصلی می‌انجامد. به عنوان مثال: دستگاه خودپرداز، که در آن یک وکیل از اطلاعات بانکی در سرور خارجی وجود دارد.

وکالت مجازی

در مواجهه به شیء پیچیده یا سنگین وزن (از نظر حافظه)، در بعضی موارد نشان دادن تنها بدنه‌ای از شیء می‌تواند مفیدتر باشد. وقتی که تصویر ایجاد شده اندازه بزرگی داشته باشد، می‌تواند توسط یک وکیل مجازی، که بر روی شیء واقعی پیاده‌سازی شده، نشان داده شود.

وکالت امنیتی

برای محافظت از کنترل دسترسی‌ها می‌توان این وظیفه را به یک وکیل سپرد.

مثال

#C

interface ICar
{
    void DriveCar();
}

// Real Object
public class Car : ICar
{
    public void DriveCar()
    {
        Console.WriteLine("Car has been driven!");
    }
}

//Proxy Object
public class ProxyCar : ICar
{
    private Driver driver;
    private ICar realCar;

    public ProxyCar(Driver driver)
    {
        this.driver = driver;
        this.realCar = new Car();
    }

    public void DriveCar()
    {
        if (driver.Age <= 16)
            Console.WriteLine("Sorry, the driver is too young to drive.");
        else
            this.realCar.DriveCar();
     }
}

public class Driver
{
    private int Age { get; set; }

    public Driver(int age)
    {
        this.Age = age;
    }
}

// How to use above Proxy class?
private void btnProxy_Click(object sender, EventArgs e)
{
    ICar car = new ProxyCar(new Driver(16));
    car.DriveCar();

    car = new ProxyCar(new Driver(25));
    car.DriveCar();
}

خروجی

Sorry, the driver is too young to drive.
Car has been driven!

یادداشت:

  • وکیل ممکن است اطلاعاتی از شیء حقیقی را از کاربر مخفی کند.
  • پروکسی ممکن است بهینه‌سازی‌هایی انجام دهد. به‌طور مثال فراخوانی تنها در هنگام نیاز.
  • وکیل ممکن است کارهای اضافه‌تری در قبال شیء اصلی انجام دهد، مثل انجام حسابرسی‌ها.
  • الگوی وکالت با عنوان الگوی جانشینی نیز شناخته می‌شود.

++C

class ICar {
public:
  virtual void DriveCar() = 0;
};

class Car : public ICar {
  void DriveCar() override {
    std::cout <<"Car has been driven!";
  }
};

class ProxyCar : public ICar {
private:
  ICar* realCar = new Car();
  int _driver_age;

public:
  ProxyCar (const int driver_age) : _driver_age(driver_age) {}

  void DriveCar() {
    if (_driver_age> 16)
      realCar->DriveCar();
    else
      std::cout <<"Sorry, the driver is too young to drive.";
  }

};

// How to use above Proxy class?
void main()
{
    ICar* car = new ProxyCar(16);

    car->DriveCar();

    delete car;

    car = new ProxyCar(25);

    car->DriveCar();

    delete car;
}

کریستال

abstract class AbstractCar
  abstract def drive
end

class Car <AbstractCar
  def drive
    puts "Car has been driven!"
  end
end

class Driver
  getter age : Int32

  def initialize(@age)
  end
end

class ProxyCar <AbstractCar
  private getter driver : Driver
  private getter real_car : AbstractCar

  def initialize(@driver)
    @real_car = Car.new
  end

  def drive
    if driver.age <= 16
      puts "Sorry, the driver is too young to drive."
    else
      @real_car.drive
    end
  end
end
# Program
driver = Driver.new(16)
car = ProxyCar.new(driver)
car.drive

driver = 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 pattern
unit DesignPattern.Proxy;

interface

type
    // Car Interface
    ICar = interface
      procedure DriveCar;
    end;

    // TCar class, implementing ICar
    TCar = Class(TInterfacedObject, ICar)
      class function New: ICar;
      procedure DriveCar;
    End;

    // Driver Interface
    IDriver = interface
      function Age: Integer;
    end;

    // TDriver Class, implementing IDriver
    TDriver = Class(TInterfacedObject, IDriver)
    private
      FAge: Integer;
    public
      constructor Create(Age: Integer); Overload;
      class function New(Age: Integer): IDriver;
      function Age: Integer;
    End;

    // Proxy Object
    TProxyCar = Class(TInterfacedObject, ICar)
    private
      FDriver: IDriver;
      FRealCar: ICar;
    public
      constructor Create(Driver: IDriver); Overload;
      class function New(Driver: IDriver): ICar;
      procedure DriveCar;
    End;

implementation

{ TCar Implementation }

class function TCar.New: ICar;
begin
     Result := Create;
end;

procedure TCar.DriveCar;
begin
     WriteLn('Car has been driven!');
end;

{ TDriver Implementation }

constructor TDriver.Create(Age: Integer);
begin
     inherited Create;
     FAge := Age;
end;

class function TDriver.New(Age: Integer): IDriver;
begin
     Result := Create(Age);
end;

function TDriver.Age: Integer;
begin
     Result := FAge;
end;

{ TProxyCar Implementation }

constructor TProxyCar.Create(Driver: IDriver);
begin
     inherited Create;
     Self.FDriver  := Driver;
     Self.FRealCar := TCar.Create AS ICar;
end;

class function TProxyCar.New(Driver: IDriver): ICar;
begin
     Result := Create(Driver);
end;

procedure TProxyCar.DriveCar;
begin
     if (FDriver.Age <= 16)
        then WriteLn('Sorry, the driver is too young to drive.')
        else FRealCar.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 جلوی دسترسی‌های متعدد به تصویر را می‌گیرد و دسترسی به آن از سامانه دیگر موجب بهینه سازی در استفاده از حافظه خواهد بود. لازم به ذکر است که هرچند فراخوانی کاهلانه‌ای که در این مثال نمایش داده شده جزو الگوی وکالت اصلی نیست، در حقیقت یک ویژگی پیشرفته‌تر است که توسط الگوی وکالت امکان‌پذیر شده‌است.

interface Image {
    public void displayImage();
}

// On System A
class RealImage implements Image {

    private String filename = null;
    /**
     * Constructor
     * @param filename
     */
    public RealImage(final String filename) {
        this.filename = filename;
        loadImageFromDisk();
    }

    /**
     * Loads the image from the disk
     */
    private void loadImageFromDisk() {
        System.out.println("Loading   " + filename);
    }

    /**
     * Displays the image
     */
    public void displayImage() {
        System.out.println("Displaying " + filename);
    }

}

// On System B
class ProxyImage implements Image {

    private RealImage image = null;
    private String filename = null;
    /**
     * Constructor
     * @param filename
     */
    public ProxyImage(final String filename) {
        this.filename = filename;
    }

    /**
     * Displays the image
     */
    public void displayImage() {
        if (image == null) {
           image = new RealImage(filename);
        }
        image.displayImage();
    }

}

class ProxyExample {

   /**
    * Test method
    */
   public static void main(final String[] arguments) {
        final Image image1 = new ProxyImage("HiRes_10MB_Photo1");
        final Image image2 = new ProxyImage("HiRes_10MB_Photo2");

        image1.displayImage(); // loading necessary
        image1.displayImage(); // loading unnecessary
        image2.displayImage(); // loading necessary
        image2.displayImage(); // loading unnecessary
        image1.displayImage(); // loading unnecessary
    }
}

خروجی برنامه:

Loading   HiRes_10MB_Photo1
Displaying HiRes_10MB_Photo1
Displaying HiRes_10MB_Photo1
Loading   HiRes_10MB_Photo2
Displaying HiRes_10MB_Photo2
Displaying HiRes_10MB_Photo2
Displaying HiRes_10MB_Photo1

جستارهای وابسته

منابع

پیوند به بیرون

Strategi Solo vs Squad di Free Fire: Cara Menang Mudah!