Также известен как Facade

Фасад

Суть паттерна

Предоставляет единый простой интерфейс к множеству интерфейсов в некоторой сложной подсистеме.

Проблема

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

В результате, бизнес-логика ваших классов тесно переплетается с деталями реализации сторонних классов. Такой код довольно сложно понимать и поддерживать.

Решение

Фасад — это простой интерфейс работы со сложной подсистемой, содержащей множество классов. Фасад может иметь урезанный интерфейс, не имеющий 100% функциональности, которую можно достичь, используя сложную подсистему напрямую. Но он предоставляет именно те фичи, которые нужны клиенту, и скрывает все остальное.

Фасад полезен, если вы используете какую-то сложную библиотеку со множеством подвижных частей, но вам нужна только часть её возможностей.

К примеру, программа, заливающая видео котиков в социальные сети, может использовать профессиональную библиотеку сжатия видео. Но все что нужно клиентскому коду этой программы — простой метод encode(filename). Создав класс с таким методом, вы реализуете свой первый фасад.

Аналогия из жизни

Заказ товаров по телефону

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

Он предоставляет вам простой интерфейс к системе создания заказа, платёжной системе и отделу доставки.

Структура

Схема структуры классов паттерна Фасад
  1. Сложная подсистема состоит из кучи разнообразных классов. Для того, чтобы заставить их что-то делать, нужно знать подробности устройства подсистемы, порядок инициализации объектов и так далее.

    Классы подсистемы не знают о существовании Фасада и работают друг с другом напрямую.

  2. Фасад предоставляет быстрый доступ к определённой функциональности подсистемы.

    Он «знает» каким классам нужно переадресовать запрос и какие данные для этого нужны.

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

    Может использоваться как Клиентом так и другими Фасадами.

  4. Клиент использует Фасад вместо прямой работы с объектами сложной подсистемы.

Псевдокод

// Классы сложного стороннего фреймворка конвертации видео. Мы не контролируем
// этот код, поэтому не можем его упростить.

class VideoFile
// ...

class OggCompressionCodec
// ...

class MPEG4CompressionCodec
// ...

class CodecFactory
// ...

class BitrateReader
// ...

class AudioMixer
// ...


// Вместо этого, мы создаём Фасад — простой интерфейс для работы со сложным
// фреймворком. Фасад не имеет всей функциональности фреймворка, но зато
// скрывает его сложность от клиентов.
class VideoConvertor is
    method convertVideo(filename, format):File is
        file = new VideoFile(filename)
        sourceCodec = new CodecFactory.extract(file)
        if (format == "mp4")
          distinationCodec = new MPEG4CompressionCodec()
        else
          distinationCodec = new OggCompressionCodec()
        buffer = BitrateReader.read(filename, sourceCodec);
        result = BitrateReader.convert(buffer, distinationCodec);
        result = (new AudioMixer()).fix(result);
        return new File(result)

// Приложение не зависит от сложного фреймворка конвертации видео. Кстати, если
// вы вдруг решите сменить фреймворк, вам нужно будет переписать только
// класс фасада.
class Application is
    method main() is
        convertor = new VideoConvertor();
        mp4video = convertor.convertVideo("youtubevideo.ogg", "mp4")

Применимость

Если нужно представить простой или урезанный интерфейс к сложной подсистеме.

Часто подсистемы усложняются по мере развития. Применение большинства паттернов приводит к появлению меньших классов, но в бо́льшем количестве. Такую подсистему проще повторно использовать и настраивать под конкретные нужды, но вместе с тем применять подсистему без настройки становится труднее. Фасад предлагает некоторый вид системы по умолчанию, устраивающий большинство клиентов.

Если вы хотите разложить подсистему на отдельные слои.

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

Шаги реализации

  1. Определите можно ли создать более простой интерфейс, чем тот, который предоставляет сложная подсистема.

    Вы на правильном пути, если этот интерфейс избавит клиента от знания о подробностях подсистемы.

  2. Создайте класс фасада, реализующий этот интерфейс. Он должен переадресовывать вызовы клиента нужным объектам подсистемы. Фасад должен будет позаботиться о том, чтобы правильно инициализировать объекты подсистемы.

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

  4. Если ответственность фасада начинает размываться, подумайте о введении дополнительных фасадов.

Преимущества и недостатки

  • Изолирует клиентов от компонентов системы.
  • Уменьшает зависимость между подсистемой и клиентами.
  • Фасад рискует стать «божественным объектом».

Отношения с другими паттернами

  • Фасад задаёт новый интерфейс, тогда как Адаптер повторно использует старый. Адаптер оборачивает только один класс, а Фасад оборачивает целую подсистему. Кроме того, Адаптер позволяет двум существующим интерфейсам работать сообща, вместо того, чтобы задать полностью новый.

  • Абстрактная фабрика может быть использована вместо Фасада для того, чтобы скрыть платформо-зависимые классы.

  • Легковес показывает как создавать много мелких объектов, а Фасад показывает как создать один объект, который отображает целую подсистему.

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

  • Фасад можно сделать Одиночкой, так как обычно нужен только один объект-фасад.

  • Фасад похож на Заместитель тем, что замещает сложную подсистему и может сам её инициализировать. Но в отличие от Фасада, Заместитель имеет тот же интерфейс, что его служебный объект, благодаря чему их можно взаимозаменять.

Реализация в различных языках программирования

Java