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ı
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ı
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
- Geary, David (22 Şubat 2002). "Proxy tasarım deseni ile kontrolü elinize alın" . JavaWorld . 2020-07-20 alındı .
- PerfectJPattern Açık Kaynak Projesi , Java'da Proxy Modelinin bileşenleştirilmiş uygulamasını sağlar
- Adaptör vs Vekil vs Cephe Desen Karşılaştırma at Wayback Machine (2012-03-11 arşivlenmiş)
- Proxy Tasarım Deseni
- Vekil desen C ++ uygulama örneği de Wayback Machine (2014-10-19 arşivlenmiş)
- Portland Kalıp Deposu'ndan proxy kalıbı açıklaması

