Различия между шаблоном прокси и декоратором

136

Можете ли вы дать какое-нибудь хорошее объяснение, в чем разница между Proxy и Decorator ?

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

Вопрос в том, остается ли прокси, созданный с помощью агрегации, прокси или, скорее, декоратором ? Разрешено ли (по определению в шаблонах GoF) создавать прокси с агрегацией?

Лукаш Жешотарски
источник
2
Некоторые ссылки: Прокси и декоратор
Сотириос Делиманолис
5
Откуда вы взяли, что Proxy использует композицию, а Decorator - агрегацию?
CPerkins
1
@CPerkins см. Мой комментарий к ответу Рахула Трипати.
Лукаш Жешотарский
1
А также декоратор ( patterns.cs.up.ac.za/examples/ch2/decorator-theory.cs ) - очевидно, агрегация, прокси ( patterns.cs.up.ac.za/examples/ch2/proxy-theory.cs ) - очевидно состав.
hyankov

Ответы:

18

Вот прямая цитата из GoF (стр. 216).

Хотя декораторы могут иметь такую ​​же реализацию, что и прокси, декораторы имеют другое назначение. Декоратор добавляет одну или несколько обязанностей к объекту, тогда как прокси контролирует доступ к объекту.

Прокси-серверы различаются по степени их реализации как декоратора. Прокси-сервер защиты может быть реализован точно так же, как декоратор. С другой стороны, удаленный прокси-сервер не будет содержать прямой ссылки на его реальный объект, а будет содержать только косвенную ссылку, такую ​​как «идентификатор хоста и локальный адрес на хосте». Виртуальный прокси начинается с косвенной ссылки, такой как имя файла, но в конечном итоге получает и использует прямую ссылку.

Популярные ответы показывают, что Прокси-сервер знает конкретный тип своего делегата. Из этой цитаты видно, что это не всегда так.

Разница между Proxy и Decorator согласно GoF в том, что Proxy ограничивает клиента. Декоратора нет. Proxy может ограничить то , что клиент делает , контролируя доступ к функциональным возможностям ; или он может ограничить то, что клиент знает , выполняя действия, которые невидимы и неизвестны клиенту. Decorator делает обратное: он улучшает то, что делает его делегат, так, чтобы это было видно клиентам.

Можно сказать, что Proxy - это черный ящик, а Decorator - это белый ящик.

Отношения композиции между оболочкой и делегатом - это неправильное отношение, на котором следует сосредоточиться при противопоставлении прокси и декоратора, поскольку композиция - это общая черта этих двух шаблонов. Отношения между оболочкой и клиентом - вот что отличает эти два шаблона.

  • Decorator информирует и уполномочивает своего клиента.
  • Прокси-сервер ограничивает и лишает возможности своего клиента.
jaco0646
источник
116

Настоящая разница не в праве собственности (состав против агрегирования), а скорее в информации о типе.

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

Но Прокси-сервер всегда знает (более) конкретный тип делегата. Другими словами, Прокси-сервер и его делегат будут иметь один и тот же базовый тип, но Прокси указывает на некоторый производный тип. Decorator указывает на его собственный базовый тип. Таким образом, разница заключается в информации о типе делегата во время компиляции.

На динамическом языке, если делегат внедрен и имеет тот же интерфейс, то разницы нет.

Ответ на ваш вопрос - «Да».

cdunn2001
источник
2
«Но доверенное лицо всегда знает (более) конкретный тип делегата». Я не думаю, что это правда. Представьте себе удаленный прокси. Механизму прокси не нужно знать какие-либо особенности удаленного объекта. Удаленная система регистрирует объект с указанным интерфейсом. И локальный прокси предоставляет тот же интерфейс.
Алексей
3
Я прошел курс по этому поводу в Amazon от приглашенного лектора, который знал свое дело. Существует разница между использованием исполняемого файла «прокси» (например, с веб-службой) и шаблона проектирования прокси. UML шаблона Proxy и шаблона Decorator могут быть разными. Но ничто не мешает прокси-серверу иметь тот же API, что и его делегат. Декоратор - это строгое подмножество прокси, но декоратор все равно может называться прокси в зависимости от того, гарантированно ли базовый API будет таким же.
cdunn2001,
85

Шаблон декоратора фокусируется на динамическом добавлении функций к объекту, тогда как шаблон прокси ориентирован на управление доступом к объекту.

РЕДАКТИРОВАТЬ:-

Связь между прокси и реальным объектом обычно устанавливается во время компиляции, прокси каким-то образом создает его экземпляр, тогда как декоратор назначается субъекту во время выполнения, зная только интерфейс субъекта.

Рахул Трипати
источник
5
Однако прокси можно использовать для добавления функций. Подумайте о прокси AOP.
Сотириос Делиманолис
5
Полностью согласен, сэр. Другими словами, я бы хотел преобразовать то, что я имел в виду, было с Proxy Pattern, прокси-класс может скрыть подробную информацию об объекте от своего клиента. Поэтому при использовании Proxy Pattern мы обычно создаем экземпляр abject внутри прокси-класса. А при использовании шаблона декоратора мы обычно передаем исходный объект в качестве параметра конструктору декоратора.
Рахул Трипати
В этом случае, когда экземпляр «скрыт» в прокси, разница для меня очевидна (как я уже писал), однако я думаю, что часто люди вызывают прокси-классы, которые принимают прокси-объект, который был передан как параметр конструктора. В этом случае для меня разница в добавлении новых функций или управлении (очень) незначительна.
Лукаш Жешотарски
5
Связь между прокси и реальным объектом обычно устанавливается во время компиляции, прокси каким-либо образом создает его экземпляр, тогда как декоратор или адаптер назначаются объекту во время выполнения, зная только интерфейс субъекта. Надеюсь, это имеет смысл !!! :)
Рахул Трипати
1
Вы могли бы добавить эту строчку к своему ответу.
Лукаш Жешотарски
49

Декоратор получает ссылку на декорированный объект (обычно через конструктор), в то время как Прокси отвечает за это сам.

Прокси-сервер может вообще не создавать экземпляр объекта-оболочки (например, ORM для предотвращения ненужного доступа к БД, если поля / геттеры объекта не используются), в то время как Decorator всегда содержит ссылку на фактический завернутый экземпляр.

Прокси-сервер обычно используется фреймворками для добавления безопасности или кеширования / бездействия и создается фреймворком (а не самим обычным разработчиком).

Декоратор обычно используется для добавления нового поведения к старым или устаревшим классам самим разработчиком на основе интерфейса, а не фактического класса (поэтому он работает с широким спектром экземпляров интерфейса, прокси - это конкретный класс).

gavenkoa
источник
22

Ключевые отличия:

  1. Прокси-сервер предоставляет тот же интерфейс. Decorator предоставляет улучшенный интерфейс.
  2. Декоратор и прокси имеют разные цели, но похожую структуру. Оба описывают, как обеспечить уровень косвенного обращения к другому объекту, а реализации сохраняют ссылку на объект, которому они направляют запросы.
  3. Декоратор можно рассматривать как вырожденный композит только с одним компонентом. Однако декоратор добавляет дополнительные обязанности - он не предназначен для агрегирования объектов.
  4. Декоратор поддерживает рекурсивную композицию
  5. Класс Decorator объявляет композиционное отношение к интерфейсу LCD (наименьший знаменатель класса), и этот член данных инициализируется в его конструкторе.
  6. Используйте прокси для ленивой инициализации, повышения производительности за счет кеширования объекта и контроля доступа к клиенту / вызывающему

В исходной статье отлично цитируются сходства и различия.

Связанные вопросы / ссылки по SE:

Когда использовать шаблон декоратора?

В чем точная разница между шаблонами адаптера и прокси?

Равиндра бабу
источник
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;
    } 
}

Обратите внимание, как я сказал это плюс одно от другого ищущего работу , а не 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 обычно самостоятельно управляет жизненным циклом своего объекта службы, тогда как состав декораторов всегда контролируется клиентом.

Али Баят
источник