В компьютерном программировании , то прокси - модель является разработка программного обеспечения шаблон . Прокси , в самом общем виде представляет собой функционирующую класс как интерфейс к чему - то еще. Прокси-сервер может взаимодействовать с чем угодно: сетевым подключением, большим объектом в памяти, файлом или каким-либо другим ресурсом, который стоит дорого или невозможно скопировать. Короче говоря, прокси - это объект-оболочка или агент, который вызывается клиентом для доступа к реальному обслуживающему объекту за кулисами. Использование прокси может быть просто пересылкойк реальному объекту, или может предоставить дополнительную логику. В прокси-сервере могут быть предоставлены дополнительные функции, например кэширование, когда операции с реальным объектом являются ресурсоемкими, или проверка предварительных условий перед вызовом операций с реальным объектом. Для клиента использование прокси-объекта аналогично использованию реального объекта, поскольку оба реализуют один и тот же интерфейс.
Обзор [ править ]
Шаблон проектирования Proxy [1] - это один из двадцати трех хорошо известных шаблонов проектирования GoF, которые описывают, как решать повторяющиеся проблемы проектирования для разработки гибкого и многократно используемого объектно-ориентированного программного обеспечения, то есть объектов, которые легче реализовать, изменить, тестирование и повторное использование.
Какие проблемы может решить шаблон проектирования прокси? [2] [ редактировать ]
- Доступ к объекту должен контролироваться.
- При доступе к объекту должны быть предоставлены дополнительные функции.
Например, при доступе к конфиденциальным объектам должна быть возможность проверить наличие у клиентов необходимых прав доступа.
Какое решение описывает шаблон проектирования прокси? [ редактировать ]
Определите отдельный Proxy
объект, который
- может использоваться как замена другого объекта (
Subject
) и - реализует дополнительную функциональность для управления доступом к этому предмету.
Это позволяет работать с Proxy
объектом для выполнения дополнительных функций при доступе к субъекту. Например, чтобы проверить права доступа клиентов, обращающихся к чувствительному объекту.
Чтобы действовать вместо субъекта, прокси-сервер должен реализовывать Subject
интерфейс. Клиенты не могут сказать, работают ли они с предметом или его прокси.
См. Также схему классов и последовательности UML ниже.
Структура [ править ]
Схема классов и последовательности UML [ править ]
В приведенной выше UML - диаграмме классов , то Proxy
орудия класса Subject
интерфейса , так что он может выступать в качестве замены для Subject
объектов. Он поддерживает ссылку ( realSubject
) на замещенный объект ( RealSubject
), чтобы он мог пересылать запросы к нему ( realSubject.operation()
).
Диаграмма последовательности показывает взаимодействия во время выполнения: Client
объект работает через Proxy
объект, который управляет доступом к RealSubject
объекту. В этом примере Proxy
объект пересылает запрос объекту RealSubject
, который его выполняет.
Диаграмма классов [ править ]
Возможные сценарии использования [ править ]
Удаленный прокси [ править ]
При распределенной связи объектов локальный объект представляет удаленный объект (принадлежащий другому адресному пространству). Локальный объект является прокси для удаленного объекта, и вызов метода для локального объекта приводит к вызову удаленного метода для удаленного объекта. Примером может служить реализация банкомата , где банкомат может содержать прокси-объекты для банковской информации, которая существует на удаленном сервере.
Виртуальный прокси [ править ]
Вместо сложного или тяжелого объекта в некоторых случаях может быть предпочтительным каркасное изображение. Когда базовое изображение огромно по размеру, оно может быть представлено с помощью виртуального прокси-объекта, загружающего реальный объект по запросу.
Прокси-сервер защиты [ править ]
Прокси-сервер защиты может использоваться для управления доступом к ресурсу на основе прав доступа.
Пример [ править ]
В Wikibook Computer Science Design Patterns есть страница по теме: Реализации прокси на разных языках |
C # [ править ]
интерфейс ICar { void DriveCar () ; }// Открытый класс реального объекта Car : ICar { public void DriveCar () { Console . WriteLine ( «Машину проехали!» ); } }// Открытый класс прокси-объекта ProxyCar : ICar { частный драйвер драйвера ; частный ICar realCar ; public ProxyCar ( драйвер драйвера ) { this . драйвер = водитель ; это . realCar = новая машина (); } public void DriveCar () { if ( driver . Age < 16 ) Console . WriteLine ( «Извините, водитель еще слишком молод для вождения.» ); еще это . realCar . DriveCar (); } }открытый класс Driver { public int Age { получить ; набор ; } public Driver ( int age ) { this . Возраст = возраст ; } }// Как использовать вышеуказанный прокси-класс? private void btnProxy_Click ( отправитель объекта , EventArgs e ) { ICar car = new ProxyCar ( новый драйвер ( 15 )); машина . DriveCar (); car = новый ProxyCar ( новый драйвер ( 25 )); машина . DriveCar (); }
Выход
Извините, водитель слишком молод для управления автомобилем.Машину пригнали!
Примечания:
- Прокси-сервер может скрыть от клиента информацию о реальном объекте.
- Прокси-сервер может выполнять оптимизацию как загрузку по запросу.
- Прокси-сервер может выполнять дополнительную работу, например, аудит.
- Шаблон проектирования прокси также известен как шаблон суррогатного проектирования.
C ++ [ править ]
#include <iostream>#include <память>class ICar { public : virtual ~ ICar () { std :: cout << "Деструктор ICar!" << std :: endl ; } виртуальная пустота DriveCar () = 0 ; };class Car : public ICar { public : void DriveCar () override { std :: cout << "Автомобиль проехал!" << std :: endl ; } };class ProxyCar : public ICar { public : ProxyCar ( int driver_age ) : driver_age_ ( driver_age ) {} void DriveCar () переопределить { if ( driver_age_ > 16 ) { real_car_ -> DriveCar (); } else { std :: cout << "Извините, водитель слишком молод для вождения." << std :: endl ; } } частное : станд :: unique_ptr < ИКАР > real_car_ = станд :: make_unique < Car > (); int driver_age_ ; };Int основной () { станд :: unique_ptr < ИКАР > автомобиль = станд :: make_unique < ProxyCar > ( 16 ); автомобиль -> DriveCar (); car = std :: make_unique < ProxyCar > ( 25 ); автомобиль -> DriveCar (); }
Кристалл [ править ]
абстрактный класс AbstractCar abstract def drive endclass Car < AbstractCar def drive ставит "Автомобиль проехал!" конец конецclass Возраст получателя драйвера : Int32 def инициализировать ( @age ) конец конецкласс ProxyCar < AbstractCar частный добытчик водитель : водитель частный добытчик real_car : AbstractCar def initialize ( @driver ) @real_car = Автомобиль . новый конец def drive, если драйвер . age <= 16 ставит «Извините, водитель слишком молод для управления автомобилем». еще @real_car . привод конец конец конец# Драйвер программы = Драйвер . новый ( 16 ) автомобиль = ProxyCar . новая ( водительская ) машина . водить машинуdriver = Драйвер . new ( 25 ) car = ProxyCar . новая ( водительская ) машина . водить машину
Выход
Извините, водитель слишком молод для управления автомобилем.Машину пригнали!
Delphi / Object Pascal [ править ]
// Модуль шаблона Proxy Design DesignPattern . Прокси ;интерфейсtype // Автомобильный интерфейс ICar = interface procedure DriveCar ; конец ; // Класс TCar, реализующий ICar TCar = Class ( TInterfacedObject , ICar ) class function New : ICar ; процедура DriveCar ; Конец ; // ID интерфейса драйвераriver = interface function Age : Integer ; конец ; // Класс TDriver, реализующий IDriver TDriver = Class ( TInterfacedObject , IDriver ) private FAge : Integer ; открытый конструктор Create ( Age : Integer ) ; Перегрузка ; функция класса New ( Возраст : Целое число ) : IDriver ; функция Возраст : Целое число ; Конец ; // Прокси-объект TProxyCar = Class ( TInterfacedObject , ICar ) private FDriver : IDriver ; FRealCar : ICar ; публичный конструктор Create ( Driver : IDriver ) ; Перегрузка ; функция класса New ( Драйвер : IDriver ) : ICar ; процедура DriveCar ; Конец ; выполнение{Реализация TCar} функция класса TCar . Новое : ICar ; begin Результат : = Создать ; конец ;процедура TCar . DriveCar ; begin WriteLn ( «Машину проехали!» ) ; конец ;{Реализация TDriver}конструктор TDriver . Создать ( Возраст : Целое число ) ; begin унаследовано Create ; FAge : = Возраст ; конец ; функция класса TDriver . Новое ( Возраст : Целое число ) : IDriver ; begin Результат : = Создать ( Возраст ) ; конец ;функция TDriver . Возраст : целое число ; begin Результат : = FAge ; конец ;{Реализация TProxyCar}конструктор TProxyCar . Создать ( Драйвер : IDriver ) ; begin унаследовано Create ; Сам . FDriver : = Драйвер ; Сам . FRealCar : = TCar . Создать AS ICar ; конец ; функция класса TProxyCar . Новое ( Драйвер : IDriver ) : ICar ; begin Результат : = Создать ( Драйвер ) ; конец ;процедура TProxyCar . DriveCar ; begin if ( FDriver . Age <= 16 ) then WriteLn ( 'Извините, драйвер слишком молод для управления.' ) else FRealCar . DriveCar () ; конец ;конец .
использование
программа Project1 ; {$ APPTYPE Console} использует DesignPattern . Прокси в DesignPattern.Proxy.pas ; начать TProxyCar . Новое ( TDriver . New ( 16 )) . DriveCar ; TProxyCar . Новое ( TDriver . New ( 25 )) . DriveCar ; конец .
Выход
Извините, водитель слишком молод для управления автомобилем.Машину пригнали!
Java [ править ]
Следующий пример Java иллюстрирует шаблон «виртуальный прокси». Класс ProxyImage используется для доступа к удаленному методу.
В примере сначала создается интерфейс, по которому шаблон создает классы. Этот интерфейс содержит только один метод отображения изображения, называемый displayImage () , который должен быть закодирован всеми реализующими его классами.
Прокси-класс ProxyImage работает в другой системе, чем сам класс реального изображения, и может представлять реальное изображение RealImage там. Информация об изображении доступна с диска. Используя шаблон прокси, код ProxyImage избегает многократной загрузки изображения, получая доступ к нему из другой системы в режиме экономии памяти. Ленивая загрузка, продемонстрированная в этом примере, не является частью шаблона прокси, а просто преимуществом, которое стало возможным благодаря использованию прокси.
интерфейс изображения { общедоступный void displayImage (); }// В системе класс RealImage реализует изображение { private final String filename ; / ** * Конструктор * @param filename * / public RealImage ( String filename ) { this . имя файла = имя файла ; loadImageFromDisk (); } / ** * Загружает изображение с диска * / private void loadImageFromDisk () { System . из . println ( "Загрузка" + имя файла ); } / ** * Отображает изображение * / public void displayImage () { System . из . println ( "Отображение" + имя файла ); } }// В системе B класс ProxyImage реализует Image { private final String filename ; частное изображение RealImage ; / ** * Конструктор * @param filename * / public ProxyImage ( String filename ) { this . имя файла = имя файла ; } / ** * Отображает изображение * / public void displayImage () { if ( image == null ) { image = new RealImage ( filename ); } изображение . displayImage (); } }class ProxyExample { / ** * Тестовый метод * / public static void main ( final String [] arguments ) { Image image1 = new ProxyImage ( "HiRes_10MB_Photo1" ); Изображение image2 = новое ProxyImage ( "HiRes_10MB_Photo2" ); изображение1 . displayImage (); // загружаем необходимое изображение1 . displayImage (); // загрузка ненужной image2 . displayImage (); // загрузка необходимо image2 . displayImage (); // загружаем ненужное изображение1 . displayImage (); // загрузка ненужных } }
Выход
Загрузка HiRes_10MB_Photo1Отображение HiRes_10MB_Photo1Отображение HiRes_10MB_Photo1Загрузка HiRes_10MB_Photo2Отображение HiRes_10MB_Photo2Отображение HiRes_10MB_Photo2Отображение HiRes_10MB_Photo1
JavaScript [ править ]
// Класс драйвера class Driver { constructor ( age ) { this . age = age } }// Класс автомобиля class Car { drive () { console . log ( 'Машину проехали!' ) } }// прокси - класс автомобиля класса ProxyCar { конструктор ( драйвер ) { это . car = new Автомобиль () this . driver = driver } drive () { if ( this . driver . age <= 16 ) { console . log ( 'Извините, драйвер слишком молод для управления.' ) } else { this . машина . drive () } } }// Запускаем программу const driver = new Driver ( 16 ) const car = new ProxyCar ( driver ) car . диск ()Const драйвер2 = новый драйвер ( 25 ) Const car2 = новый ProxyCar ( драйвер2 ) car2 . диск ()
Выход
Извините, водитель слишком молод для управления автомобилем.Машину пригнали!
PHP [ править ]
<? php интерфейс Изображение { общедоступная функция displayImage (); }// В системе класс RealImage реализует Image { private string $ filename = null ; публичная функция __construct ( строка $ filename ) { $ this -> filename = $ filename ; $ this -> loadImageFromDisk (); } / ** * Загружает изображение с диска * / private function loadImageFromDisk () { echo "Loading { $ this -> filename } " . \ PHP_EOL ; } / ** * Отображает изображение * / общедоступная функция displayImage () { echo "Отображение { $ this -> filename } " . \ PHP_EOL ; } }// В системе B класс ProxyImage реализует Image { private ? Изображение $ image = null ; частная строка $ filename = null ; публичная функция __construct ( строка $ filename ) { $ this -> filename = $ filename ; } / ** * Отображает изображение * / общедоступная функция displayImage () { if ( $ this -> image === null ) { $ this -> image = new RealImage ( $ this -> filename ); } $ this -> изображение -> displayImage (); } }$ image1 = новый ProxyImage ( "HiRes_10MB_Photo1" ); $ image2 = новый ProxyImage ( "HiRes_10MB_Photo2" );$ image1 -> displayImage (); // Загрузка необходимого $ image1 -> displayImage (); // Загрузка ненужных $ image2 -> displayImage (); // Загрузка необходимого $ image2 -> displayImage (); // Загружаем ненужное $ image1 -> displayImage (); // Загружаем ненужное
Выход
Загрузка HiRes_10MB_Photo1 Отображение HiRes_10MB_Photo1 Отображение HiRes_10MB_Photo1 Загрузка HiRes_10MB_Photo2 Отображение HiRes_10MB_Photo2 Отображение HiRes_10MB_Photo2 Отображение HiRes_10MB_Photo1
Python [ править ]
«» « Шаблон Пример прокси. „“» От аЬса импорт ABCMeta , abstractmethodNOT_IMPLEMENTED = "Вы должны это реализовать."класс AbstractCar : __metaclass__ = ABCMeta @abstractmethod def drive ( self ): поднять NotImplementedError ( NOT_IMPLEMENTED )class Car ( AbstractCar ): def drive ( self ) -> None : print ( «Автомобиль проехал!» )class Driver : def __init__ ( self , age : int ) -> None : self . age = возрастclass ProxyCar ( AbstractCar ): def __init__ ( self , driver ) -> None : self . car = Автомобиль () self . driver = водитель def drive ( self ) -> None : если self . водитель . age <= 16 : print ( «Извините, водитель слишком молод для управления.» ) else : self . машина . диск ()driver = Driver ( 16 ) car = ProxyCar ( водитель ) автомобиль . диск ()driver = Driver ( 25 ) car = ProxyCar ( водитель ) автомобиль . диск ()
Выход
Извините, водитель слишком молод для управления автомобилем.Машину пригнали!
Ржавчина [ править ]
trait ICar { fn drive ( & self );}struct Car {} impl ICar for Car { fn drive ( & self ) { println ! ( «Машину пригнали!» ); }}impl Car { fn new () -> Автомобиль { Автомобиль {} }}struct ProxyCar <' a > { real_car : & ' ИКАР , driver_age : i32 ,}impl <' a > ICar для ProxyCar <' a > { fn drive ( & self ) { если сам . driver_age > 16 { я . real_car . диск (); } else { println ! ( «Извините, водитель слишком молод, чтобы водить машину». ) } }}impl <' a > ProxyCar <' a > { fn new ( driver_age : i32 , other_car : & ' a ICar ) -> ProxyCar { ProxyCar { real_car : другой_кар , driver_age : driver_age , } }}# [cfg (тест)]mod tests { используйте super :: * ; #[тест] fn test_underage () { let car = Car :: new (); let proxy_car = ProxyCar :: new ( 16 , & автомобиль ); proxy_car . диск (); } #[тест] fn test_can_drive () { let car = Car :: new (); let proxy_car = ProxyCar :: new ( 17 , & автомобиль ); proxy_car . диск (); }}
Выход
Извините, машина слишком молода для вас.Машину пригнали!
См. Также [ править ]
- Составной узор
- Шаблон декоратора
- Ленивая инициализация
Ссылки [ править ]
- ^ Эрих Гамма, Ричард Хелм, Ральф Джонсон, Джон Влиссидес (1994). Паттерны проектирования: элементы объектно-ориентированного программного обеспечения многократного использования . Эддисон Уэсли. стр. 207ff . ISBN 0-201-63361-2.CS1 maint: несколько имен: список авторов ( ссылка )
- ^ «Шаблон проектирования прокси - проблема, решение и применимость» . w3sDesign.com . Проверено 12 августа 2017 .
- ^ «Шаблон проектирования прокси - структура и взаимодействие» . w3sDesign.com . Проверено 12 августа 2017 .
Внешние ссылки [ править ]
Викискладе есть медиафайлы, связанные с шаблоном прокси . |
- Гири, Дэвид (22 февраля 2002 г.). «Возьмите под свой контроль шаблон проектирования прокси» . JavaWorld . Проверено 20 июля 2020 .
- PerfectJPattern Open Source Project , предоставляет компонентную реализацию шаблона прокси на Java
- Сравнение адаптера, прокси и фасада на Wayback Machine (архивировано 11 марта 2012 г.)
- Шаблон проектирования прокси
- Пример реализации C ++ шаблона прокси на Wayback Machine (архивировано 19 октября 2014 г.)
- Описание шаблона прокси из Портлендского репозитория шаблонов