Использование нескольких декораторов для добавления функциональности к объекту? - PullRequest
6 голосов
/ 05 апреля 2011

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

Я немного запутался, когда используется несколько декораторов и как получить доступ к расширенным функциям. Обычно при просмотре примеров шаблона декоратора, что-то вроде этого показано:

IBusinessObject businessObject = new MailDecorator(
    new SmsDecorator(
        new FaxDecorator(
            new BusinessObject()
        )
    )
);

Идея заключается в том, чтобы взять объект и динамически добавлять функции почты, смс и факса. Теперь, если вы хотите отправить письмо, которое является методом, предоставляемым классом MailDecorator, вы можете сделать что-то вроде этого:

If(businessObject is MailDecorator)
{
    ((MailDecorator) businessObject).SendMail();
}  

Однако это не сработает, если вы захотите отправить SMS или факс, так как в обычной реализации шаблона декоратора у вас не будет доступа к объекту, на который ссылается декоратор.

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

Стандартное определение

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

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

1 Ответ

15 голосов
/ 05 апреля 2011

Это распространенное заблуждение шаблона декоратора. Что вы можете сделать с шаблоном декоратора, так это расширить функциональность , а не API .

Что это значит?
Это означает, что вы можете добавить новую функциональность в методы, предоставляемые API, в вашем случае IBusinessObject. Допустим, у вашего интерфейса есть метод XmlDocument Export(), который реализован в BusinessObject и возвращает данные в экземпляре BusinessObject в экземпляре XmlDocument.
Теперь вы можете создать LoggingDecorator, который реализует метод Export следующим образом:

public XmlDocument Export()
{
    _logger.Log("Exporting...");
    var result = _decoratedObject.Export();
    _logger.Log("Done exporting...");
    return result;
}

Или вы можете создать BusinessObjectSigningExportDecorator, который подписывает возвращаемое XmlDocument, используя алгоритм xml-dsig:

public XmlDocument Export()
{
    var result = _decoratedObject.Export();
    return SignXmlDocument(result);
}

Затем вы могли бы использовать их вместе так:

IBusinessObject businessObject = new LoggingDecorator(
    new BusinessObjectSigningExportDecorator(
        new BusinessObject()
    )
);

var xmlDocument = businessObject.Export();

Звонок на Export теперь будет писать сообщения журнала и подписывать экспорт xml. Но вы все равно можете использовать BusinessObject без декоратора или только с одним из декораторов.

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

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

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

...