Декоратор (Decorator) представляет собой немного спорный паттерн. Его почти всегда можно заменить чем-нибудь другим. Например, Компоновщиком или Строителем.
Но все же Декоратор вполне может найти свое место в вашем проекте. Не зря его активно используют при разработке библиотек ввода-вывода. Особенно это заметно в Java.
В основе паттерна Декоратор лежит базовый интерфейс (или абстрактный класс). Для него создаются реализации, выполняющие полезные действия. Декоратор при этом выступает в качестве прозрачной обертки над реализациями, имея тот же самый интерфейс. Он делегирует все вызовы оборачиваемому объекту, но добавляет свои специфические преобразования.
Преимущество от использования Декоратора заключается в том, что он позволяет комбинировать цепочки обернутых объектов произвольной сложности. В результате удается избежать ненужного дублирования кода.
Рассмотрим пример. Создадим небольшое приложение, которое применяет графические фильтры к загруженному изображению. Фильтры могут накладываться, поэтому Декоратор позволит нам динамически создавать комбинированные фильтры, доступные для повторного использования.
Спроектируем простой интерфейсный класс ImageFilter. Заголовочный файл imagefilter.h:
#ifndef IMAGEFILTER_H
#define IMAGEFILTER_H
#include <QPixmap>
class ImageFilter {
public:
    ImageFilter();
    virtual ~ImageFilter();
    virtual QPixmap apply( const QPixmap& pix ) = 0;
};
#endif // IMAGEFILTER_H
Он имеет всего одну чисто виртуальную функцию apply(), которая принимает на вход QPixmap, и возвращает результат применения фильтра.
Поскольку нам интересны как фильтры по отдельности, так и комбинации фильтров, то каждая реализация станет потенциальным Декоратором. Начнем с фильтра отзеркаливания.
В Qt довольно легко создать подобный эффект. Объявим класс MirroredImageFilter, наследующий ImageFilter, в mirroredimagefilter.h:
#ifndef MIRROREDIMAGEFILTER_H
#define MIRROREDIMAGEFILTER_H
#include <imagefilter.h>
#include <memory>
class MirroredImageFilter : public ImageFilter {
public:
    explicit MirroredImageFilter( const std::shared_ptr< ImageFilter >& filter = nullptr );
    QPixmap apply( const QPixmap& pix );
private:
    std::shared_ptr< ImageFilter > m_filter;
};
#endif // MIRROREDIMAGEFILTER_H
В качестве параметра конструктор принимает указатель на оборачиваемый фильтр. Если параметр равен nullptr, то класс ничего не декорирует, и выступает в качестве самостоятельной реализации. А вот и она, в файле mirroredimagefilter.cpp:
#include "mirroredimagefilter.h"
MirroredImageFilter::MirroredImageFilter( const std::shared_ptr< ImageFilter >& filter ) :
    m_filter( filter ) {
}
QPixmap MirroredImageFilter::apply( const QPixmap& pix ) {
    QPixmap pixResult = pix;
    if( m_filter ) {
        pixResult = m_filter->apply( pix );
    }
    return QPixmap::fromImage( pixResult.toImage().mirrored( true, false ) );
}
Один фильтр уже есть. Проверим его работу. Файл main.cpp:
#include <QApplication>
#include <QFileDialog>
#include <QLabel>
#include "mirroredimagefilter.h"
int main( int argc, char** argv ) {
    QApplication app( argc, argv );
    QString fileName = QFileDialog::getOpenFileName(
        nullptr,
        "Load Image",
        QString(),
        "Images (*.jpg *.png *.bmp)"
    );
    QPixmap pix;
    if( pix.load( fileName ) ) {
        QLabel lblMirrored;
        lblMirrored.setPixmap( MirroredImageFilter().apply( pix ) );
        lblMirrored.show();
        return app.exec();
    }
    return 0;
}
Эта программа уже что-то делает, но пока что Декоратора здесь еще нет. Он появится, когда мы добавим хотя бы еще один фильтр. Займемся этим прямо сейчас.
Пусть второй фильтр-Декоратор умеет осуществлять поворот изображения на указанный угол. Посмотрим на соответствующий заголовочный файл rotatedimagefilter.h:
#ifndef ROTATEDIMAGEFILTER_H
#define ROTATEDIMAGEFILTER_H
#include "imagefilter.h"
#include <memory>
class RotatedImageFilter : public ImageFilter {
public:
    RotatedImageFilter( double angle = 90.0, const std::shared_ptr< ImageFilter >& filter = nullptr );
    QPixmap apply( const QPixmap& pix );
private:
    double m_angle;
    std::shared_ptr< ImageFilter > m_filter;
};
#endif // ROTATEDIMAGEFILTER_H
А вот и реализация в rotatedimagefilter.cpp:
#include "rotatedimagefilter.h"
RotatedImageFilter::RotatedImageFilter( double angle, const std::shared_ptr< ImageFilter >& filter ) :
    m_angle( angle ), m_filter( filter ) {
}
QPixmap RotatedImageFilter::apply( const QPixmap& pix ) {
    QPixmap pixResult = pix;
    if( m_filter ) {
        pixResult = m_filter->apply( pix );
    }
    return pixResult.transformed( QTransform().rotate( m_angle ) );
}
Теперь у нас есть два фильтра. Каждый из них можно использовать отдельно, а можно скомбинировать в цепочку. Попробуем все это на практике (файл main.cpp):
#include <QApplication>
#include <QFileDialog>
#include <QLabel>
#include "mirroredimagefilter.h"
#include "rotatedimagefilter.h"
int main( int argc, char** argv ) {
    QApplication app( argc, argv );
    QString fileName = QFileDialog::getOpenFileName(
        nullptr,
        "Load Image",
        QString(),
        "Images (*.jpg *.png *.bmp)"
    );
    QPixmap pix;
    if( pix.load( fileName ) ) {
        QLabel lblMirrored;
        lblMirrored.setPixmap( MirroredImageFilter().apply( pix ) );
        lblMirrored.show();
        QLabel lblRotated;
        lblRotated.setPixmap( RotatedImageFilter().apply( pix ) );
        lblRotated.show();
        QLabel lblCombined;
        lblCombined.setPixmap(
            RotatedImageFilter( 45.0, std::make_shared< MirroredImageFilter >() ).apply( pix )
        );
        lblCombined.show();
        return app.exec();
    }
    return 0;
}
В результате запуска программы на экране появятся три QLabel: с отзеркаленным изображением, с повернутым на 90 градусов изображением и с изображением, которое было сначала отзеркалено, а потом повернуто на 45 градусов:

Поскольку мы создали всего два фильтра, то существенную выгоду от использования паттерна Декоратор увидеть сложно. Но с ростом числа реализаций количество их возможных комбинаций будет возрастать очень быстро. В этом случае Декоратор в сочетании со Стратегией или каким-нибудь другим полиморфным подходом окажется весьма привлекательным решением.
Скачать исходники с примером использования паттерна Декоратор в Qt