Patterns. Паттерн 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. Особливості використання відкритих та закритих класів підсистем. Будь-яка підсистема може мати загальнодоступні класи (інтерфейси) та класи, які закриті від іншого коду. Фасад забезпечує доступ до загальнодоступних (відкритих) інтерфейсів, хоча й інші класи підсистеми можуть бути відкритими.

 


Споріднені теми