Паттерны проектирования. Паттерн Facade (Фасад)

Паттерн Facade (Фасад)


Содержание


Поиск на других ресурсах:

1. Общие сведения. Рисунок

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

Чтобы облегчить проектирование сложной системы, эта система разбивается на ряд более мелких подсистем. При этом важно чтобы:

  • подсистемы зависели друг от друга как минимум;
  • обмен информацией между подсистемами был минимальным.

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

На рисунке 1 показана суть использования объекта фасада для упрощенного доступа клиентов к подсистемам.

Паттерн Facade (Фасад)Рисунок 1. Паттерн Facade (Фасад)

На основе подхода, изображенном на рисунке 1, базируется паттерн Facade (Фасад). В систему вводится класс (интерфейс), содержащий упрощенные средства (методы, поля и т.п.), обеспечивающие доступ к более сложным подсистемам.

Способов реализации этого класса может быть несколько.

 

2. Пример решения задачи с использованием паттерна Facade
2.1. Условие задачи

Задано взаимодействие между двумя подсистемами (рисунок 2), представленными интерфейсами InterfaceA и InterfaceB. Используя паттерн Facade реализовать унифицированный интерфейс для взаимодействия этих подсистем.

Паттерны проектирования. Подсистемы A, B и взаимодействие клиентов с этими подсистемами

Рисунок 2. Подсистемы A, B и взаимодействие клиентов с этими подсистемами

 

2.2. Решение (рисунок)

На рисунке 2 изображено решение с использованием паттерна Facade задачи, изображенной на рисунке 1.

Паттерн Facade. Взаимодействие между подсистемами через унифицированный интерфейс

Рисунок 3. Взаимодействие между подсистемами через унифицированный интерфейс с использованием паттерна Facade

 

2.3. Текст решения задачи на языке C++

 

#include <iostream>
using namespace std;

// Паттерн Facade (Фасад)
// ----------------------------------------
// Классы подсистемы 1
// Интерфейс
class InterfaceA abstract
{
public:
  virtual void MethodA() = 0;
};

class ClassA1 : public InterfaceA
{
public:
  void MethodA() override
  {
    cout << "ClassA1::MethodA()" << endl;
  }
};

class ClassA2 : public InterfaceA
{
public:
  void MethodA() override
  {
    cout << "ClassA2::MethodA()" << endl;
  }
};

// ----------------------------------------
// Классы подсистемы 2
// Интерфейс
class InterfaceB abstract
{
public:
  virtual void MethodB() = 0;
};

class ClassB1 : public InterfaceB
{
public:
  void MethodB() override
  {
    cout << "ClassB1::MethodB()" << endl;
  }
};

class ClassB2 : public InterfaceB
{
public:
  void MethodB() override
  {
    cout << "ClassB2::MethodB()" << endl;
  }
};

// Класс, что есть фасадом.
// В классе реализуется упрощенный интерфейс
// для наиболее распространенного случая
// это есть основная идея
class Facade
{
public:
  void FacadeMethodA(InterfaceA* obj)
  {
    obj->MethodA();
  }

  void FacadeMethodB(InterfaceB* obj)
  {
    obj->MethodB();
  }
};

void main()
{
  // Клиентский код
  // Реальные реализации
  ClassA1* objA1 = new ClassA1;
  ClassA2* objA2 = new ClassA2;
  ClassB1* objB1 = new ClassB1;
  ClassB2* objB2 = new ClassB2;

  // Клиенты A, B
  Facade* ClientA = new Facade;
  Facade* ClientB = new Facade;

  // Вызовы методов
  // Доступ клиента A к методу MethodA() класса ClassA1
  ClientA->FacadeMethodA(objA1);

  // Доступ клиента B к методу MethodB() класса ClassB2
  ClientB->FacadeMethodB(objB2);

  // Доступ клиента B к методу MethodA() класса ClassA2
  ClientB->FacadeMethodA(objA2);

  // Освободить память после демонстрации паттерна
  if (objA1) delete objA1;
  if (objA2) delete objA2;
  if (objB1 != nullptr) delete objB1;
  if (objB2) delete objB2;
  if (ClientA) delete ClientA;
  if (ClientB) delete ClientB;
}

 

3. Случаи применения паттерна Facade

Паттерн Facade используется в следующих случаях.

  1. Когда необходимо обеспечить простой интерфейс к сложной подсистеме. В процессе развития подсистемы изменяются и могут усложняться. Изменения требуют дополнительных настроек под определенные требования. Паттерн Facade предлагает некоторый вариант настроек системы по умолчанию, удовлетворяющий большинство клиентов. При этом, если нужно осуществить более сложные настройки, то соответствующие объекты могут обращаться к объектам подсистемы напрямую минуя паттерн Facade.
  2. Когда между клиентами и классами реализации абстракции существует множество зависимостей. Паттерн Facade отделяет подсистему от клиентов и других систем. Таким образом, обеспечивается лучшая переносимость и независимость.
  3. Необходимость разбиения подсистемы на отдельные слои. В этом случае определяются точки входа на каждый уровень подсистемы и в каждой точке входа формируется фасад. Здесь важно установление правила обмена между подсистемами только через фасады.

 

4. Структура паттерна Facade (рисунок). Учасники паттерна

На рисунке 4 изображена структура паттерна Facade. Эта структура обобщена.

Паттерн Facade. Структура

Рисунок 4. Структура паттерна Facade

В вышеприведенной структуре (рисунок 4) класс (участник) Facade выполняет следующие функции:

  • определяет классы подсистемы, к которым реализуется запрос;
  • делает перенаправление (делегирование) запросов клиентов тем объектам подсистемы, которые для них подходят.

Классы подсистемы выполняют следующие функции:

  • реализуют функциональность подсистемы;
  • выполняют работу, установленную объектом Facade;
  • не хранят ссылки на объект Facade (не «знают» о существовании фасада).

 

5. Отношения

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

 

6. Результаты

Использование паттерна Facade дает следующие преимущества.

  1. Отделение (изоляция) клиентов от составляющих подсистемы уменьшает количество используемых объектов клиентами. Это, в свою очередь, упрощает работу с подсистемой.
  2. Снижается связь между подсистемой и ее клиентами. Это дает возможность видоизменять компоненты, не затрагивая при этом клиентов. Использование фасадов позволяет разбить систему на слои и структурировать зависимости между объектами. Если между объектами подсистемы есть сложные циклические зависимости, то с помощью фасадов эти зависимости можно избежать.

Как следствие, изменение одной подсистемы будет минимально влиять (или вообще не влиять) на другую подсистему. Это упрощает переносимость системы на другие платформы.

  1. При необходимости клиентский код может напрямую обращаться к классам подсистемы. В этом случае фасад не устанавливает никаких препятствий. Таким образом, существует выбор между общим и упрощенным.

 

7. Особенности реализации

При реализации паттерна Facade следует обратить внимание на следующие вопросы.

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

Существует и другой подход. Использование объекта Facade с различными объектами, настроенными под конкретные подсистемы.

  1. Особенности использования открытых и закрытых классов подсистем. Любая подсистема может иметь общедоступные классы (интерфейсы) и классы, закрытые от другого кода. Фасад обеспечивает доступ к общедоступным (открытым) интерфейсам, хотя и другие классы подсистемы могут быть открыты.

 


Связанные темы