Відмінності між проксі і декоративними малюнками


136

Чи можете ви дати хороше пояснення, в чому різниця між проксі та декоратором ?

Основна відмінність, яку я бачу, полягає в тому, що коли ми припускаємо, що Proxy використовує композицію, а Decorator використовує агрегацію, то, здається, зрозуміло, що за допомогою декількох (один або більше) декораторів ви можете змінювати / додавати функціональні можливості до наявного екземпляра (прикрашати), тоді як Проксі має власний внутрішній примірник проксі-класу і делегує йому додавання додаткових функцій (поведінка проксі).

Питання полягає в тому, - чи проксі, створений за допомогою агрегації, все ще є проксі або швидше декоратором ? Чи дозволено (за визначенням у шаблонах GoF) створювати проксі з агрегацією?


2
Деякі посилання: Проксі та декоратор
Sotirios Delimanolis

5
Звідки ви взяли думку про те, що Proxy використовує композицію, а Decorator використовує агрегацію?
CPerkins

1
@CPerkins бачити мій коментар щодо відповіді Рахула Трипаті.
Łukasz Rzeszotarski

1
А також декоратор ( pattern.cs.up.ac.za/examples/ch2/decorator-theory.cs ) - очевидно, агрегація, проксі ( pattern.cs.up.ac.za/examples/ch2/proxy-theory.cs ) - очевидно склад.
hyankov

Відповіді:


17

Ось пряма цитата з Міністерства фінансів (стор. 216).

Хоча декоратори можуть мати подібні втілення як проксі, але декоратори мають інше призначення. Декоратор додає один або кілька обов'язків до об'єкта, тоді як проксі керує доступом до об'єкта.

Проксі-агенти різняться за ступенем, в якому вони реалізовані як декоратор. Проксі-захист може бути реалізований точно як декоратор. З іншого боку, віддалений проксі не буде містити прямого посилання на його реальну тему, а лише непряму посилання, наприклад "ідентифікатор хоста та локальна адреса хоста". Віртуальний проксі починається з непрямого посилання, такого як ім'я файлу, але з часом отримує та використовує пряму посилання.

Популярні відповіді свідчать про те, що проксі-сервер знає конкретний тип свого делегата. З цієї цитати ми бачимо, що це не завжди так.

Різниця між проксі та декоратором відповідно до GoF полягає в тому, що проксі обмежує клієнта. Декоратор ні. Проксі може обмежувати, що робить клієнт , контролюючи доступ до функціональності; або він може обмежити те, що знає клієнт , виконуючи невидимі і невідомі дії для клієнта. Декоратор робить навпаки: він покращує те, що робить його делегат у спосіб, який видно клієнтам.

Можна сказати, що проксі - це чорна скринька, а декоратор - біла коробка.

Співвідношення композиції між обгорткою та делегатом - це неправильне співвідношення, на яке слід зосереджуватись, коли контрастувати Проксі з Декоратором, оскільки композиція є особливістю цих двох шаблонів. Зв’язок між обгорткою та клієнтом - це те, що відрізняє ці дві моделі.

  • Декоратор інформує та надає повноваження своєму клієнту.
  • Проксі обмежує і позбавляє права клієнта.

113

Справжня різниця - це не власність (склад проти агрегації), а швидше інформація про тип.

Декоратор буде завжди пройшов delegatee. Proxy може створити його сам, або він може мати його вводили.

Але проксі завжди знає (більше) конкретний тип делегата. Іншими словами, проксі та його делегат матимуть однаковий базовий тип, але проксі вказує на деякий похідний тип. декоратор вказує на його власний базовий тип. Таким чином, різниця полягає в інформації про час делегата за часом збирання.

У динамічній мові, якщо делегат вводиться ін'єкційно і має той самий інтерфейс, різниці немає.

Відповідь на ваше запитання - «Так».


2
"Але проксі завжди знає (більше) конкретний тип делегата." Я не думаю, що це правда. Уявіть віддалений проксі. Проксі-механізму не потрібно знати будь-яку специфіку віддаленого об'єкта. Віддалена система реєструє об'єкт із заданим інтерфейсом. І локальний проксі відкриває той же інтерфейс.
Олексій

3
Я взяв заняття з цього питання в Amazon від відвідувача викладача, який знав його речі. Існує різниця між використанням виконуваного "проксі" (наприклад, за допомогою веб-сервісу) та шаблоном дизайну проксі. UML-схеми проксі-шаблону та шаблону декоратора можуть бути різними. Але ніщо не заважає проксі мати той самий API, що і його делегат. Decorator - це суворий підмножина проксі, але декоратор все ще може називатися проксі, залежно від того, чи гарантовано API, який знаходиться в основі.
cdunn2001

85

Шаблон « Декоратор» фокусується на динамічному додаванні функцій до об’єкта, тоді як Проксі- шаблон - на контролі доступу до об’єкта.

Редагувати: -

Зв'язок між проксі і реальним суб'єктом зазвичай встановлюється під час компіляції, проксі певним чином створює його, тоді як декоратор призначається суб'єкту під час виконання, знаючи лише інтерфейс предмета.


5
Проксі-сервер все ще може використовуватися для додавання функціональності. Подумайте про проксі-сервера AOP.
Сотіріос Деліманоліс

5
Повністю згоден сер. Я б перетворив, що іншими словами, те, що я мав на увазі під "Проксі-шаблоном", клас проксі може приховати детальну інформацію про об'єкт від свого клієнта. Тому, використовуючи шаблон проксі, ми зазвичай створюємо екземпляр abject всередині проксі-класу. І коли ми використовуємо шаблон декоратора, ми зазвичай передаємо початковий об’єкт як параметр конструктору декоратора.
Рахул Трипаті

У цьому випадку, коли екземпляр "захований" в проксі, для мене різниця зрозуміла (як я писав), проте я думаю, що часто люди називають проксі-класи, які беруть проксі-об'єкт, переданий як параметр конструктора. У цьому випадку різниця в додаванні нового функціоналу чи контролю для мене (дуже) мала.
Łukasz Rzeszotarski

5
Зв'язок між проксі та реальним суб'єктом зазвичай встановлюється під час компіляції, проксі певним чином створює його, тоді як декоратор або адаптер призначаються суб'єкту під час виконання, знаючи лише інтерфейс теми. Сподіваюся, що має сенс !!! :)
Rahul Tripathi

1
Це ви можете додати цей рядок до своєї відповіді.
Łukasz Rzeszotarski

49

Декоратор отримує посилання на декорований об’єкт (як правило, через конструктор), в той час як Proxy відповідає за це сам.

Проксі може взагалі не створювати об'єкт обгортання (як це роблять ORM для запобігання зайвого доступу до БД, якщо поля об’єктів / getters не використовуються), в той час як Decorator завжди утримує посилання на фактично завернутий екземпляр.

Проксі, який зазвичай використовується в рамках для додання безпеки або кешування / лазерної роботи і створюється за рамками (а не самим звичайним розробником).

Декоратор зазвичай використовується для додавання нової поведінки до старих або застарілих класів самим розробником на основі інтерфейсу, а не фактичного класу (тому він працює в широкому діапазоні екземплярів інтерфейсу, проксі - навколо конкретного класу).


22

Основні відмінності:

  1. Проксі надає той же інтерфейс. Decorator забезпечує розширений інтерфейс.
  2. Декоратор та проксі мають різні цілі, але схожі структури. Обидва описують, як забезпечити рівень непрямості для іншого об'єкта, а реалізації зберігають посилання на об'єкт, на який вони пересилають запити.
  3. Декоратор може розглядатися як вироджений композит із лише одним компонентом. Однак декоратор додає додаткові обов'язки - він не призначений для об'єднання об'єктів.
  4. Декоратор підтримує рекурсивну композицію
  5. Клас « Декоратор» оголошує співвідношення композиції до інтерфейсу LCD (найнижчий клас-знаменник), і цей член даних ініціалізується у своєму конструкторі.
  6. Використовуйте проксі для лінивої ініціалізації, підвищення продуктивності, кешуючи об’єкт та контролюючи доступ до клієнта / абонента

Стаття про джерелознавство прекрасно цитує подібності та відмінності.

Питання / посилання, пов'язані з ДП:

Коли використовувати візерунок декоратора?

Яка точна різниця між моделями адаптерів та проксі?


3

Проксі та декоратор відрізняються між собою за призначенням та місцем, де вони зосереджені на внутрішній реалізації. Проксі - це використання віддаленого, перехресного процесу або крос-мережевого об'єкта, як якщо б це був локальний об'єкт. Decorator - це додавання нової поведінки до оригінального інтерфейсу.

Незважаючи на те, що обидві структури схожі за структурою, основна частина складності проксі полягає в забезпеченні належного зв’язку з вихідним об'єктом. Декоратор, з іншого боку, орієнтується на реалізацію додаткової поведінки.


Що ви кажете, що відрізняється від інших 4 відповідей, які вже є тут?
Стівен Рауч

Я не знаю, чи все там. Я просто відчув бажання передзвонити, прочитавши попередні відповіді.
Джеймс Лін

1

Знадобився час, щоб зрозуміти цю відповідь і що вона насправді означає. Кілька прикладів повинні зробити це більш зрозумілим.

Proxy перший:

public interface Authorization {
    String getToken();
} 

І:

// goes to the DB and gets a token for example
public class DBAuthorization implements Authorization {
    @Override
    public String getToken() {
        return "DB-Token";
    }
}

І є цей абонент Authorization, досить німий:

class Caller {
    void authenticatedUserAction(Authorization authorization) {
        System.out.println("doing some action with : " + authorization.getToken());
    }
}

Нічого незвичного поки що, правда? Отримайте маркер від певної служби, використовуйте цей маркер. Тепер до картинки постає ще одна вимога, додайте ведення журналу: тобто щоразу записуйте маркер. У цьому випадку це просто, просто створіть Proxy:

public class LoggingDBAuthorization implements Authorization {

    private final DBAuthorization dbAuthorization = new DBAuthorization();

    @Override
    public String getToken() {
        String token = dbAuthorization.getToken();
        System.out.println("Got token : " + token);
        return token;
    }
}

Як би ми цим скористалися?

public static void main(String[] args) {
    LoggingDBAuthorization loggingDBAuthorization = new LoggingDBAuthorization();

    Caller caller = new Caller();
    caller.authenticatedUserAction(loggingDBAuthorization);
}

Зауважте, що LoggingDBAuthorization має примірник DBAuthorization. І те, LoggingDBAuthorizationі DBAuthorization реалізувати Authorization .

  • Проксі-сервер містить деяку конкретну реалізацію ( DBAuthorization) базового інтерфейсу ( Authorization). Іншими словами, проксі точно знає , що проксі.

Decorator:

Він починається приблизно так само Proxy, як і з інтерфейсом:

public interface JobSeeker {
    int interviewScore();
}

та його реалізація:

class Newbie implements JobSeeker  {
    @Override
    public int interviewScore() {
        return 10;
    }
}

А тепер ми хочемо додати більш досвідченого кандидата, який додає його бал за співбесіду плюс показник від іншого JobSeeker:

@RequiredArgsConstructor 
public class TwoYearsInTheIndustry implements JobSeeker {

    private final JobSeeker jobSeeker;

    @Override
    public int interviewScore() {
        return jobSeeker.interviewScore() + 20;
    } 
}

Зверніть увагу, як я сказав, що плюс інший JobSeeker , ні Newbie . A Decoratorне знає , що саме прикрашає, знає лише договір цього прикрашеного екземпляра (він знає про JobSeeker). Зверніть увагу, що це не схоже на Proxy; що, навпаки, точно знає, що це прикрашає.

Ви можете запитати, чи є в цьому випадку різниця між двома моделями дизайну? Що робити, якщо ми спробували написати Decoratorяк Proxy?

public class TwoYearsInTheIndustry implements JobSeeker {

    private final Newbie newbie = new Newbie();

    @Override
    public int interviewScore() {
        return newbie.interviewScore() + 20;
    }
}

Це, безумовно, варіант і підкреслює, наскільки близькі ці зразки; вони все ще призначені для різних сценаріїв, як пояснено в інших відповідях.


1

Проксі надає той самий інтерфейс загорнутому об'єкту, Decorator надає йому розширений інтерфейс, а Proxy зазвичай самостійно керує життєвим циклом його сервісного об’єкта, тоді як складом декораторів завжди керує клієнт.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.