Когда необходимо использовать шаблон декоратора? Если возможно, приведите пример из реальной жизни, который хорошо подходит для этого шаблона.
Потоки в Java - подклассы InputStream
и OutputStream
являются прекрасными примерами шаблона декоратора.
В качестве примера, запись файла на диск:
File toWriteTo = new File("C:\\temp\\tempFile.txt");
OutputStream outputStream = new FileOutputStream(toWriteTo);
outputStream.write("Sample text".getBytes());
Затем, если вам потребуются некоторые дополнительные функции, касающиеся записи на диск:
File toWriteTo = new File("C:\\temp\\tempFile.txt");
OutputStream outputStream =
new GZIPOutputStream(new FileOutputStream(toWriteTo));
outputStream.write("Sample text".getBytes());
Просто «сцепив» конструкторы, вы можете создать довольно мощные способы записи на диск . Прелесть этого способа в том, что позже вы можете добавить различные (в этом примере) реализации OutputStream
. Кроме того, каждая реализация не знает, как работают другие - все они работают по одному и тому же контракту. Это также упрощает изолированное тестирование каждой реализации.
В шаблонах проектирования Head First Design Patterns есть еще несколько примеров из «реального мира». Кажется, что у O'Reilly есть их образец главы, которая находится на шаблоне декоратора, бесплатно; Google обнаружил эту ссылку: PDF
Взгляните на описание Фаулера; он дает конкретный пример, относящийся к книгам / видео и декоратору, "заимствованному", вы можете найти его здесь .
Два реальных примера:
Системы улучшения предметов в Diablo 2 и Final Fantasy 7. У оружия и доспехов есть гнезда или слоты. Во время игры игрок кладет в эти слоты улучшения (драгоценные камни, руны или материалы). Каждое улучшение имеет индивидуальный эффект (скажем, 8 очков огненного урона или 10% похищения маны). Итак, когда вы взмахиваете мечом, он наносит базовый урон плюс урон, добавляемый каждым улучшением, которое вы добавили. Это очень близко соответствует шаблону декоратора.
Одно из самых крутых - и наиболее буквальных - применений, которые я видел, - это реализация возможности отмены в старые плохие времена одноуровневой отмены. Для программы векторного рисования с несколькими выбранными объектами разных цветов: реализуйте команду для изменения всех их цветов. И сделайте это невозможным. Это было сделано путем применения Decorator, который был вызван в потоке getColor (), так что когда они были нарисованы, они были нарисованы в новом цвете; по сути, собственные методы getColor () объектов были отменены. Итак, они появились в новом цвете. Отменить было так же просто, как удалить декоратор со всех объектов; фиксация действия заключалась в применении цвета из декоратора к объектам с последующим его удалением. Гораздо проще, чем вести таблицу того, какие предметы были раскрашены и каковы были их первоначальные цвета.
Из Gang of Four:
Инструментарий графического пользовательского интерфейса, например, должен позволять добавлять свойства, такие как границы, или поведение, такое как прокрутка, к любому компоненту пользовательского интерфейса.
...
Декоратор соответствует интерфейсу компонента, который он декорирует, так что его присутствие прозрачно для клиентов компонента. Декоратор пересылает запросы компоненту и может выполнять дополнительные действия (например, рисовать границы) до или после пересылки. Прозрачность позволяет рекурсивно вложить декораторы, тем самым обеспечивая неограниченное количество дополнительных обязанностей.
Назначение шаблона Decorator:
Прикрепить дополнительные обязанности к объекту динамически. Декораторы предоставляют гибкую альтернативу созданию подклассов для расширения функциональности. [via В первую очередь: шаблоны проектирования ]
Самым интенсивным использованием шаблона декоратора являются графические интерфейсы пользователя и классы java.io. Существует бесплатная глава Head First: Design Patterns о шаблоне декоратора [link] , в которой приведены некоторые другие примеры:
Мы повторно рассмотрим типичное чрезмерное использование наследования, и вы узнаете, как украсьте свои классы во время выполнения, используя форма объектной композиции. Почему? Как только вы освоите технику украшения, вы сможете подарить ваши (или чужие) объекты новые обязанности без каких-либо изменения кода в базовом классы.
Вы также можете прочитать Шаблон декоратора на примере [PDF] , в котором шаблон декоратора используется в оценочном приложении.
Если вы знакомы с разработкой Swing на Java (наряду с другими инструментами графического интерфейса пользователя), вы увидите, что часто используется шаблон декоратора. У вас может быть конструктор, который принимает определенный компонент, а затем добавляет ему функциональность.
Вот хорошая статья, в которой в качестве примера используется Swing .
Вы просили пример реального мира, так вот: скачайте (или просмотрите) DonsProxy с github:
git://github.com/DonBranson/DonsProxy.git
DonsProxy в основном использует шаблон WireTap, чтобы позволить вам наблюдать или извлекать HTTP трафик, плюс он позволяет вам изменять поведение соединения для имитации неоптимальных соединений. Я использую паттерн Decorator для модификации каналов на основе опций пользователя. Опции командной строки или GUI (в зависимости от того, какой View они используют) позволяют вводить задержку и пропускную способность, среди прочего. Когда они вводят задержку, это добавляет LatencyDecorator к каналу; если они дросселируют пропускную способность, это добавляет ThrottleDecorator к каналу. Поскольку здесь используется паттерн декоратора, они могут смешивать и сочетать поведение по своему усмотрению.