Паттерн Декоратор и создание фильтров изображений в Qt

Паттерн Декоратор и создание фильтров изображений в Qt

Паттерн Декоратор (Decorator) представляет собой немного спорный паттерн. Его почти всегда можно заменить чем-нибудь другим. Например, Компоновщиком или Строителем.

Но все же Декоратор вполне может найти свое место в вашем проекте. Не зря его активно используют при разработке библиотек ввода-вывода. Особенно это заметно в Java.

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

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

Рассмотрим пример. Создадим небольшое приложение, которое применяет графические фильтры к загруженному изображению. Фильтры могут накладываться, поэтому Декоратор позволит нам динамически создавать комбинированные фильтры, доступные для повторного использования.

Интерфейс графического фильтра

Спроектируем простой интерфейсный класс ImageFilter. Заголовочный файл imagefilter.h:

Он имеет всего одну чисто виртуальную функцию apply(), которая принимает на вход QPixmap, и возвращает результат применения фильтра.

Поскольку нам интересны как фильтры по отдельности, так и комбинации фильтров, то каждая реализация станет потенциальным Декоратором. Начнем с фильтра отзеркаливания.

Фильтр отзеркаливания изображения

В Qt довольно легко создать подобный эффект. Объявим класс MirroredImageFilter, наследующий ImageFilter, в mirroredimagefilter.h:

В качестве параметра конструктор принимает указатель на оборачиваемый фильтр. Если параметр равен nullptr, то класс ничего не декорирует, и выступает в качестве самостоятельной реализации. А вот и она, в файле mirroredimagefilter.cpp:

Пробный запуск

Один фильтр уже есть. Проверим его работу. Файл main.cpp:

Эта программа уже что-то делает, но пока что Декоратора здесь еще нет. Он появится, когда мы добавим хотя бы еще один фильтр. Займемся этим прямо сейчас.

Фильтр поворота изображения

Пусть второй фильтр-Декоратор умеет осуществлять поворот изображения на указанный угол. Посмотрим на соответствующий заголовочный файл rotatedimagefilter.h:

А вот и реализация в rotatedimagefilter.cpp:

Все вместе

Теперь у нас есть два фильтра. Каждый из них можно использовать отдельно, а можно скомбинировать в цепочку. Попробуем все это на практике (файл main.cpp):

В результате запуска программы на экране появятся три QLabel: с отзеркаленным изображением, с повернутым на 90 градусов изображением и с изображением, которое было сначала отзеркалено, а потом повернуто на 45 градусов.

Выводы

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

Понравилась статья? Поделиться с друзьями:
Добавить комментарий