Шаблон дизайна декоратора - PullRequest
       14

Шаблон дизайна декоратора

5 голосов
/ 03 февраля 2009

Я только начинаю изучать шаблоны проектирования, и у меня есть два вопроса, связанных с Декоратором ...

Мне было интересно, почему шаблон декоратора предлагает, чтобы декоратор реализовал все открытые методы компонента, который он декорирует?

Разве нельзя использовать класс декоратора для обеспечения дополнительного поведения, а затем использовать конкретный компонент (который передается в него) для вызова всего остального?

А во-вторых, что если конкретный компонент, который вы хотите декорировать, не имеет базового класса, из которого также может извлекать абстрактный декоратор?

Заранее спасибо!

Ответы [ 2 ]

15 голосов
/ 03 февраля 2009

Я думаю, вы неправильно поняли Декоратор. Вы думаете о простом случае расширения конкретного класса дополнительными функциями. В этом случае, да, в большинстве языков OO производный класс может просто позволить своему суперклассу обрабатывать любые нереализованные методы.

class Base {

  function foo() {
    return "foo";
  }

  function bar() {
    return "bar";
  }

}

// Not what we think of as a Decorator,
// really just a subclass.
class Decorator extends Base {

  // foo() inherits behavior from parent Base class 

  function bar() {
    return parent::bar() . "!"; // add something
  }

}

Класс Decorator не расширяет базовый класс своего "украшенного" класса. Это другой тип, в котором есть объект-член оформленного класса. Таким образом, он должен реализовывать тот же интерфейс, если только вызывать соответствующий метод декорированного объекта.

class Decorator { // extends nothing
  protected $base;

  function __construct(Base $base) {
    $this->base = $base;
  }

  function foo() {
    return $base->foo();
  }

  function bar() {
    return $base->foo() . "!"; // add something
  }

}

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

interface IBase {
  function foo();
  function bar();
}

class Base implements IBase {
  . . .
}

class Decorator implements IBase {
  . . .
}

Re: @Yossi Dahan's comment: Я вижу неоднозначность в статье в Википедии, но если вы внимательно прочитаете, она говорит, что декорируемый компонент - это поле в объекте декоратора, и что этот компонент передается в качестве аргумента конструктору декоратора. Это отличается от наследования.

Хотя в статье в Википедии говорится, что декоратор наследуется от компонента, вы должны думать об этом как о реализации интерфейса, как я показал в примере с PHP выше. Декоратор все еще должен прокси для объекта компонента, чего не было бы, если бы он унаследовал. Это позволяет декоратору декорировать объект любого класса, который реализует этот интерфейс.

Вот некоторые отрывки из «Шаблонов проектирования: элементы многократно используемого объектно-ориентированного программного обеспечения» Гаммы, Хелма, Джонсона и Влиссида:

декоратор

Намерение

Прикрепить дополнительные обязанности к объекту динамически. Декораторы обеспечивают гибкая альтернатива подклассам для расширения функциональности.

Мотивация

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

Участники

  • декоратор поддерживает ссылку на объект Component и определяет интерфейс соответствует интерфейсу компонента.
3 голосов
/ 03 февраля 2009

Мне было интересно, почему шаблон декоратора предлагает, чтобы декоратор реализовал все открытые методы компонента, который он декорирует?

Декоратор должен быть заменен на компонент, который он украшает, с дополнительной функциональностью («украшение»). Это может произойти, только если он полностью реализует интерфейс компонента.

Разве нельзя использовать класс декоратора для обеспечения дополнительного поведения, а затем использовать конкретный компонент (который передается в него) для вызова всего остального?

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

А во-вторых, что если конкретный компонент, который вы хотите декорировать, не имеет базового класса, из которого также может извлекать абстрактный декоратор?

Декораторы обычно наследуют класс компонента, который они декорируют, а не базовый компонент.

...