Шаблон "декоратор": Почему нам нужен абстрактный декоратор? [дубликат]

Этот вопрос уже имеет ответ здесь:

Этот вопрос уже задали здесь, а скорее, чем ответ на конкретный вопрос, описания того, как работы шаблона "декоратор" были даны вместо этого. Я хотел бы спросить это снова, потому что ответ не сразу очевиден для меня только путем чтения, как шаблон "декоратор" работает (я прочитал статью Википедии и раздел в книжном Заголовке Первые Шаблоны разработки).

В основном я хочу знать, почему абстрактный класс декоратора должен быть создан, который реализует (или расширяется), некоторый интерфейс (или абстрактный класс). Почему не может все новые "украшенные классы" просто реализовывать (или расширяться) основной абстрактный объект сами (вместо того, чтобы расширить абстрактный класс декоратора)?

Для создания этого более конкретным, я буду использовать пример из книги шаблонов разработки, имеющей дело с кофейными напитками:

  • Существует абстрактный названный класс компонента Beverage
  • Простые типы напитка такой как HouseBlend просто расширитесь Beverage
  • Украсить напиток, краткий обзор CondimentDecorator класс создается, который расширяется Beverage и имеет экземпляр Beverage
  • Скажите, что мы хотим добавить "молочную" приправу, класс Milk создается, который расширяется CondimentDecorator

Я хотел бы понять, почему нам было нужно CondimentDecorator класс и почему класс Milk возможно, не просто расширился Beverage сам класс и передал экземпляр Beverage в его конструкторе.

Надо надеяться, это ясно..., если не я просто хотел бы знать, почему абстрактный класс декоратора необходим для этого шаблона?Спасибо.

Править: Я пытался реализовать это, опуская абстрактный класс декоратора, и это, кажется, все еще работает. Этот абстрактный класс существует во всех описаниях этого шаблона просто, потому что он обеспечивает стандартный интерфейс для всех новых украшенных классов?

32
задан Piotr Góralczyk 27 August 2019 в 22:08
поделиться

4 ответа

Позволяет самостоятельно декорировать базовый класс различными декораторами в различных комбинациях без необходимости выведения класса для каждой возможной комбинации. Например, скажем, Вы хотите Напиток с молоком и мускатным орехом. Используя декораторы на основе абстрактного класса декораторов, вы просто оберните с Молоко и Мускатный орех декораторов. Если бы он был получен из Напиток , то вам нужно было бы иметь класс Молоко с мускатным орехом и класс Молоко с мускатным орехом и класс Мускатный орех с мускатным орехом . Вы можете представить, как это взорвется по мере увеличения количества возможных комбинаций. Использование абстрактной реализации декоратора сводит это к одной реализации класса декоратора на декорацию.

9
ответ дан 27 November 2019 в 20:21
поделиться

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

2
ответ дан 27 November 2019 в 20:21
поделиться

(Немного поздно ответить на ваш вопрос ..)

Я также потратил довольно много времени, чтобы попытаться найти ответ. В моем случае неконкретный декоратор расширяет класс, который нужно декорировать («декоратор»), вместо интерфейса, общего как для декоратора, так и для декоратора.

После прочтения из разных источников мне кажется, что помимо того, что сказал Тванфоссон , причина того, что конкретные декораторы расширяют абстрактный или более общий декоратор, заключается в том, чтобы мы не повторяли код "делегирования" снова и снова.

[Beverage]<———————[(abstract) CondimentDecorator]<—————[Milk]
[decoree ]——————<>[ adds code to efficiently    ]
                  [ forward calls to decorated  ]<—————[LemonJuice]
                  [ instance of Beverage        ]

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

Надеюсь, я был ясен ..: -S

Лично меня немного разочаровала необходимость повторения интерфейса декоратора в декораторе. Это добавляет некоторую связь, поскольку каждый раз, когда интерфейс декоратора изменяется (например, появляется больше методов), декоратор должен его догнать.

В PHP 5.3.2 (да, я знаю, что ваш вопрос связан с Java), тем не менее, должна быть возможность динамически перехватывать все вызовы методов и перенаправлять их все, при этом декоратору не нужно знать, какие методы вызываются ( тем не менее, не очень эффективным способом из-за необходимости использования Reflection API). Думаю, это уже возможно в Ruby и других языках.

PS: Это мой первый ответ в SO! ^ _ ^

11
ответ дан 27 November 2019 в 20:21
поделиться

Я задавался тем же вопросом. Возвращаясь к источнику, GOF Design Patterns, я вижу следующее в разделе 'Implementation' в главе Decorator:

"Omitting the abstract Decorator class. Нет необходимости определять абстрактный класс Decorator, если вам нужно добавить только одну ответственность. Это часто бывает, когда вы имеете дело с существующей иерархией классов, а не разрабатываете новую. В этом случае вы можете объединить ответственность Decorator за пересылку запросов к компоненту в Concrete Decorator."

Так что, по крайней мере, в этом случае, кажется, что GOF с вами согласен :-)

Я не уверен, что имеется в виду "одна ответственность". Я не уверен, означает ли более чем "одна ответственность" один конкретный декоратор, который имеет более чем одну ответственность, или более чем один конкретный декоратор, каждый из которых имеет одну ответственность. В любом случае, я не понимаю, зачем нужен абстрактный декоратор. Я думаю, что ответ tvanfosson (в его комментарии к его собственному ответу) правильный - что как только вы начинаете создавать несколько классов-декораторов, это проясняет проектное решение сгруппировать их под суперклассом. С другой стороны, когда есть только один класс, это, возможно, делает проектное решение менее ясным, если вы добавляете второй класс, который просто сидит как бессмысленный посредник между базовым компонентом и декоратором (учитывая это, вполне вероятно, что вы захотите добавить больше в какой-то момент, так что, возможно, лучше включить абстрактный декоратор даже в единственном случае...)

Во всяком случае, похоже, что это связано с тем, чтобы сделать проект ясным, а не с тем, что это разница между работающим и неработающим кодом.

11
ответ дан 27 November 2019 в 20:21
поделиться
Другие вопросы по тегам:

Похожие вопросы: