„Provide a surrogate or placeholder for another object to control access to it.“
Gang Of Four
Идеята на този design pattern е да „обвие“ обектът (Subject) с нещо като wrapper, който с помощта на дадена логика, да ограничи достъпа до обекта, с оглед например на:
1) дали изобщо имаме право да работим с обекта (security)
2) дали сега му е времето, демек, дали не може да изчакаме с инициализацията на даденият обект за да спестим ресурс (lazy loading)
3) дали вече обектът съществува и можем да го използваме наготово (Singleton)
4) дали да копираме обекта или не, в зависимост дали е бил променен (copy-on-write) или ако не – да пробутваме същият уж като копиран.
Тоест, за разлика от другите подобни design patterns, които:
1) добавят функционалност (Decorator)
2) или адаптират достъпа до даденият обект и отделно дават различен интерфейс към обекта (Adapter), при този design pattern ключовата дума е по-скоро „контрол на достъпа“.
Демек, имаме добавяне на логика но с намерение да контролираме достъпа, не да променяме или допълваме това, към което контролираме достъпа.
Контрол на достъпа, но не само от към гледна точка на сигурността. Това е само един от аспектите на този design pattern.
Може да имаме случаи, когато например да трябва предварително да проверим дали изобщо имаме обект, който да използваме.
Или дали обектът вече не съществува с оглед на това да не го създаваме пак (кеширане, подобно на Singleton design pattern).
Или например да приложим някаква валидация… и т.н…
В този смисъл на думата имаме три вида Proxy design pattern:
A remote proxy controls access to a remote object.
A virtual proxy controls access to a resource that is expensive to create.
A protection proxy controls access to a resource based on access rights.
Защо изобщо ни е нужно всичко това, този design pattern демек?
Не може ли да си напъхаме въпросната „логика на достъпа“ с самият Subject? Защо да я отделяме в друг клас, че през него да викаме Subject-а?
По принцип може но това може да „раздуе“ класа Subject и да нарушим Single Responsibility Principle.
Отделно, ако разсъждаваме по-абстрактно, често логиката, обстоятелствата, при които ни се налага да използваме даденият Subject може да не са толкова плътно свързани със самата логика на Subject-a (демек, „какво прави“ и „кога да го прави“).
Ако започнем да тъпчем логиката кога Subject-ът да се извика, в самият него, и тази логика е доста променлива например, всеки път ли трябва да го променямe (Subject-ът)?
Aко например искаме да станем в 5:00 сутринта, трябва ли да имаме тази способност в нас самите (еволюционно), след като можем да използваме будилник, който да ни събуди когато трябва? А ако утре трябва да станем в 5:30 например… хайде пак милиони години еволюция…
Как програмно се реализира Proxy design pattern?
С помощта на клас, който като аргумент в конструктора си например, приема обектът, който ще „проксираме“ (Subject) и в него (Proxy класът) ще имаме метод/методи, където ще е логиката, според която ще или не ще използваме проксираният обект. Или ще го използваме по определен начин и т.н…
Define a separate Proxy
object that:
1. can be used as substitute for another object (Subject
) and
2. implements additional functionality to control the access to this subject.
3. A proxy may hide information about the real object to the client.
4. A proxy may perform optimization like on demand loading.
5. A proxy may do additional house-keeping job like audit tasks.
6. Proxy design pattern is also known as surrogate design pattern.
This makes it possible to work through a Proxy
object to perform additional functionality when accessing a subject. For example, to check the access rights of clients accessing a sensitive object.
To act as substitute for a subject, a proxy must implement the Subject
interface. Clients can’t tell whether they work with a subject or its proxy.
Последното изречение е интересно. За да действа като Прокси, то (Проксито), както самият Subject (проксираният) трябва да имплементират един общ интерфейс. Защо? За да са взаимозаменяеми.
Литература: