Proxy kalıbı - Proxy pattern

Gelen bilgisayar programlama , vekil model bir olduğunu yazılım tasarım deseni . Bir vekil , en genel biçimde, başka bir şeye bir arayüz olarak bir sınıf işlemektedir. Proxy herhangi bir şeyle arabirim oluşturabilir: bir ağ bağlantısı, bellekteki büyük bir nesne, bir dosya veya çoğaltılması pahalı veya imkansız olan başka bir kaynak. Kısacası, proxy, sahne arkasında gerçek hizmet veren nesneye erişmek için istemci tarafından çağrılan bir sarmalayıcı veya aracı nesnedir. Proxy kullanımı , gerçek nesneye yönlendirme olabilir veya ek mantık sağlayabilir. Proxy'de, örneğin gerçek nesne üzerindeki işlemler kaynak yoğun olduğunda önbelleğe alma veya gerçek nesne üzerindeki işlemler çağrılmadan önce ön koşulların kontrol edilmesi gibi ekstra işlevsellik sağlanabilir. İstemci için, bir proxy nesnesinin kullanımı, gerçek nesnenin kullanımına benzer, çünkü her ikisi de aynı arabirimi uygular.

genel bakış

Proxy tasarım deseni, esnek ve yeniden kullanılabilir nesne yönelimli yazılım, yani uygulanması, değiştirilmesi, test edilmesi ve uygulanması daha kolay nesneler tasarlamak için yinelenen tasarım problemlerinin nasıl çözüleceğini açıklayan iyi bilinen yirmi üç GoF tasarım deseninden biridir. yeniden kullanın.

Proxy tasarım deseni hangi sorunları çözebilir?

  • Bir nesneye erişim kontrol edilmelidir.
  • Bir nesneye erişirken ek işlevsellik sağlanmalıdır.

Örneğin hassas nesnelere erişirken, istemcilerin gerekli erişim haklarına sahip olup olmadığını kontrol etmek mümkün olmalıdır.

Proxy tasarım deseni hangi çözümü tanımlar?

Ayrı bir Proxynesne tanımlayın

  • başka bir nesnenin ( Subject) yerine kullanılabilir ve
  • bu konuya erişimi kontrol etmek için ek işlevler uygular.

Bu, Proxybir özneye erişirken ek işlevsellik gerçekleştirmek için bir nesne üzerinde çalışmayı mümkün kılar . Örneğin, hassas bir nesneye erişen istemcilerin erişim haklarını kontrol etmek için.

Bir öznenin yerine geçebilmesi için bir vekilin Subjectarayüzü uygulaması gerekir . İstemciler, bir özneyle mi yoksa vekiliyle mi çalıştıklarını söyleyemez.

Ayrıca aşağıdaki UML sınıfına ve sıra şemasına bakın.

yapı

UML sınıfı ve sıra diyagramı

Image
Proxy tasarım deseni için örnek bir UML sınıfı ve sıra diyagramı.

Yukarıdaki UML sınıf diyagramında , Proxysınıf Subject, Subjectnesnelerin yerine geçebilmesi için arabirimi uygular . realSubjectDeğiştirilen nesneye ( RealSubject) bir başvuru ( ) tutar, böylece istekleri ona iletebilir ( realSubject.operation()).

Sıra diyagramı, çalışma zamanı etkileşimlerini gösterir: ClientNesne, bir Proxynesneye erişimi kontrol eden bir nesne aracılığıyla çalışır RealSubject. Bu örnekte, Proxyisteği RealSubjectgerçekleştiren öğesine isteği iletir .

Sınıf diyagramı

Image
Proxy UML
Image
LePUS3'te proxy ( efsane )

Olası kullanım senaryoları

uzak proxy

Olarak dağıtık nesne iletişim , yerel bir amacı, uzak bir nesne (farklı bir adres alanı ait bir) temsil eder. Yerel nesne, uzak nesne için bir proxy'dir ve yerel nesnede yöntem çağırma , uzak nesnede uzak yöntem çağırma ile sonuçlanır . Bir örnek , ATM'nin uzak sunucuda bulunan banka bilgileri için proxy nesneleri tutabileceği bir ATM uygulaması olabilir.

sanal proxy

Karmaşık veya ağır bir nesnenin yerine, bazı durumlarda bir iskelet temsili avantajlı olabilir. Altta yatan bir görüntünün boyutu çok büyük olduğunda, sanal bir proxy nesnesi kullanılarak temsil edilebilir ve talep üzerine gerçek nesne yüklenebilir.

Koruma proxy'si

Erişim haklarına dayalı olarak bir kaynağa erişimi kontrol etmek için bir koruma proxy'si kullanılabilir.

Misal

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
{
    public 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(15));
    car.DriveCar();

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

Çıktı

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

Notlar:

  • Bir proxy, gerçek nesne hakkındaki bilgileri istemciye gizleyebilir.
  • Bir proxy, isteğe bağlı yükleme gibi optimizasyon gerçekleştirebilir.
  • Bir vekil, denetim görevleri gibi ek ev işleri yapabilir.
  • Proxy tasarım deseni, vekil tasarım deseni olarak da bilinir.

C++

#include <iostream>
#include <memory>

class ICar {
 public:
  virtual ~ICar() { std::cout << "ICar destructor!" << std::endl; }

  virtual void DriveCar() = 0;
};

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

class ProxyCar : public ICar {
 public:
  ProxyCar(int driver_age) : driver_age_(driver_age) {}

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

 private:
  std::unique_ptr<ICar> real_car_ = std::make_unique<Car>();
  int driver_age_;
};

int main() {
  std::unique_ptr<ICar> car = std::make_unique<ProxyCar>(16);
  car->DriveCar();

  car = std::make_unique<ProxyCar>(25);
  car->DriveCar();
}

Kristal

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

Çıktı

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

Delphi / Nesne 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.

kullanım

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.

Çıktı

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

Java

Aşağıdaki Java örneği, "sanal proxy" modelini göstermektedir. ProxyImageSınıf uzak yöntem erişmek için kullanılmaktadır.

Örnek, önce kalıbın sınıfları oluşturduğu bir arabirim oluşturur. Bu arabirim, displayImage()onu uygulayan tüm sınıflar tarafından kodlanması gereken , adı verilen görüntüyü görüntülemek için yalnızca bir yöntem içerir .

Proxy sınıfı ProxyImage, gerçek görüntü sınıfının kendisinden başka bir sistemde çalışır ve RealImageoradaki gerçek görüntüyü temsil edebilir . Görüntü bilgilerine diskten erişilir. Proxy kalıbını kullanarak, kodun kodu ProxyImage, görüntünün çoklu yüklenmesini önler, diğer sistemden hafızadan tasarruf sağlayan bir şekilde erişilir. Bu örnekte gösterilen tembel yükleme, proxy modelinin bir parçası değildir, yalnızca proxy kullanımıyla mümkün kılınan bir avantajdır.

interface Image {
    public void displayImage();
}

// On System A
class RealImage implements Image {
    private final String filename;

    /**
     * Constructor
     * @param filename
     */
    public RealImage(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 final String filename;
    private RealImage image;
    
    /**
     * Constructor
     * @param filename
     */
    public ProxyImage(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) {
        Image image1 = new ProxyImage("HiRes_10MB_Photo1");
        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
    }
}

Çıktı

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

JavaScript

// Driver class
class Driver {
  constructor (age) {
    this.age = age
  }
}

// Car class
class Car {
  drive () {
    console.log('Car has been driven!')
  }
}

// Proxy car class
class ProxyCar {
  constructor (driver) {
    this.car = new Car()
    this.driver = driver
  }

  drive () {
    if (this.driver.age <= 16) {
      console.log('Sorry, the driver is too young to drive.')
    } else {
      this.car.drive()
    }
  }
}

// Run program
const driver = new Driver(16)
const car = new ProxyCar(driver)
car.drive()

const driver2 = new Driver(25)
const car2 = new ProxyCar(driver2)
car2.drive()

Çıktı

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

PHP

<?php 

interface Image
{
    public function displayImage();
}

// On System A
class RealImage implements Image
{
    private string $filename = null;

    public function __construct(string $filename)
    {
        $this->filename = $filename;
        $this->loadImageFromDisk();
    }

    /**
     * Loads the image from the disk
     */
    private function loadImageFromDisk()
    {
        echo "Loading {$this->filename}" . \PHP_EOL;
    }

    /**
     * Displays the image
     */
    public function displayImage()
    {
    	echo "Displaying {$this->filename}" . \PHP_EOL;
    }
}

// On System B
class ProxyImage implements Image
{
    private ?Image $image = null;
    private string $filename = null;

    public function __construct(string $filename)
    {
        $this->filename = $filename;
    }

    /**
     * Displays the image
     */
    public function displayImage()
    {
        if ($this->image === null) {
           $this->image = new RealImage($this->filename);
        }
        $this->image->displayImage();
    }
}


$image1 = new ProxyImage("HiRes_10MB_Photo1");
$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

Çıktı

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

piton

"""
Proxy pattern example.
"""
from abc import ABCMeta, abstractmethod


NOT_IMPLEMENTED = "You should implement this."


class AbstractCar:
    __metaclass__ = ABCMeta

    @abstractmethod
    def drive(self):
        raise NotImplementedError(NOT_IMPLEMENTED)


class Car(AbstractCar):
    def drive(self) -> None:
        print("Car has been driven!")


class Driver:
    def __init__(self, age: int) -> None:
        self.age = age


class ProxyCar(AbstractCar):
    def __init__(self, driver) -> None:
        self.car = Car()
        self.driver = driver

    def drive(self) -> None:
        if self.driver.age <= 16:
            print("Sorry, the driver is too young to drive.")
        else:
            self.car.drive()


driver = Driver(16)
car = ProxyCar(driver)
car.drive()

driver = Driver(25)
car = ProxyCar(driver)
car.drive()

Çıktı

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

Pas

trait ICar {
    fn drive(&self);
}

struct Car {}

impl ICar for Car {
    fn drive(&self) {
        println!("Car has been driven!");
    }
}

impl Car {
    fn new() -> Car {
        Car {}
    }
}

struct ProxyCar<'a> {
    real_car: &'a ICar,
    driver_age: i32,
}

impl<'a> ICar for ProxyCar<'a> {
    fn drive(&self) {
        if self.driver_age > 16 {
            self.real_car.drive();
        } else {
            println!("Sorry, the driver is too young to drive.")
        }
    }
}

impl<'a> ProxyCar<'a> {
    fn new(driver_age: i32, other_car: &'a ICar) -> ProxyCar {
        ProxyCar {
            real_car: other_car,
            driver_age: driver_age,
        }
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    
    #[test]
    fn test_underage() {
        let car = Car::new();
        let proxy_car = ProxyCar::new(16, &car);
        proxy_car.drive();
    }

    #[test]
    fn test_can_drive() {
        let car = Car::new();
        let proxy_car = ProxyCar::new(17, &car);
        proxy_car.drive();
    }
}

Çıktı

Sorry, the car is to young for you to drive.
Car has been driven!

Ayrıca bakınız

Referanslar

Dış bağlantılar