Перейти до вмісту

Фасад (шаблон проєктування)

Матеріал з Вікіпедії — вільної енциклопедії.
Діаграма класів

Фаса́д — шаблон проєктування, призначений для об'єднання групи підсистем під один уніфікований інтерфейс, надаючи доступ до них через одну точку входу. Це дозволяє спростити роботу з підсистемами.

Фасад належить до структурних шаблонів проєктування.

Складові шаблону

[ред. | ред. код]

Класи, з яких складається шаблон можна розділити на 3 частини:

  1. фасад;
  2. підсистеми;
  3. клієнти.

Ролі складових

[ред. | ред. код]

Фасад

[ред. | ред. код]
  • Визначає певним підсистемам інтерфейс, отже знає кому адресувати запити;
  • делегує запити клієнтів потрібним об'єктам підсистеми;
  • створює нові методи, котрі об'єднують виклики об'єктів системи і\або додають свою логіку;
  • приховує підсистеми;
  • зменшує кількість параметрів методів, шляхом попередньої підстановки визначених значень.

Підсистема

[ред. | ред. код]
  • реалізує функціонал, закритий та не видимий для зовнішніх компонентів
  • виконує роботу, запитану клієнтом через фасад.
  • не зберігає посилання на фасад — це означає що одна підсистема може мати довільну кількість фасадів.

Клієнт

[ред. | ред. код]
  • здійснює запити фасаду;
  • не знає про існування підсистем.

Переваги та недоліки

[ред. | ред. код]

Переваги

[ред. | ред. код]
  • Приховує реалізацію підсистеми від клієнтів, що полегшує використання підсистеми
  • Сприяє слабкій взаємодії між підсистемою та її клієнтами. Це дозволяє змінити класи, які включають підсистему, не впливаючи на клієнтів.
  • Зменшує компіляційні залежностей у великих програмних системах
  • Спрощує системи перенесення на інші платформи, оскільки менш імовірно, що для побудови однієї підсистеми потрібно побудувати всі інші

Недоліки

[ред. | ред. код]
  • Не заважає сучасним клієнтам отримувати доступ до базових класів
  • Фасад не додає жодної функції, він просто спрощує інтерфейси

Випадки використання

[ред. | ред. код]

Фасад використовується у випадках, коли потрібно:

  • спростити доступ до складної системи;
  • створити рівні доступу до системи;
  • додати стійкість до змін підсистем;
  • зменшити кількість сильних зв'язків між клієнтом та підсистемою, але залишити доступ до повної функціональності.

Зв'язок з іншими патернами

[ред. | ред. код]
  • Фасад створює новий інтерфейс доступу, адаптер — використовує старий

Реалізація

[ред. | ред. код]
Приклад реалізації на мові С++
#include <iostream>
#include <string>

using namespace std;

// Абстрактний музикант - не є обов'язковою частиною патерну, введений для спрощення коду
class Musician
{
private:
	string name;
public:
	Musician(string name)
	{
		this->name = name;
	}
	virtual ~Musician() {}
protected:
	void output(string text)
	{
		cout << this->name << " " << text << "." << endl;
	}
};
// Конкретні музиканти
struct Vocalist : public Musician
{
	Vocalist(string name) : Musician(name) {}
	void singCouplet(string coupletNumber)
	{
		string text = "заспівав куплет №" + coupletNumber;
		output(text);
	}
	void singChorus()
	{
		output("заспівав приспів");
	}
};
struct Guitarist : public Musician
{
	Guitarist(string name) : Musician(name) {}
	void playCoolOpening()
	{
		output("починає з крутого виступу");
	}
	void playCoolRiffs()
	{
		output("грає круті рифи");
	}
	void playAnotherCoolRiffs()
	{
		output("грає інші круті рифи");
	}
	void playIncrediblyCoolSolo()
	{
		output("лабає неймовірно круте соло");
	}
	void playFinalAccord()
	{
		output("закінчує пісню супер акордом");
	}
};
struct Bassist : public Musician
{
	Bassist(string name) : Musician(name) {}
	void followTheDrums()
	{
		output("слідкує за барабанами");
	}
	void changeRhythm(string type)
	{
		string text = "перейшов на ритм ";
		output(text + type);
	}
	void stopPlaying()
	{
		output("закінчує грати");
	}
};
struct Drummer : public Musician
{
	Drummer(string name) : Musician(name) {}
	void startPlaying()
	{
		output("починає грати");
	}
	void stopPlaying()
	{
		output("закінчує грати");
	}
};
// Фасад — в цьому випадку, рок-група
class BlackSabbath
{
private:
	Vocalist* vocalist;
	Guitarist* guitarist;
	Bassist* bassist;
	Drummer* drummer;
public:
	BlackSabbath()
	{
		vocalist = new Vocalist("Оззі Осборн");
		guitarist = new Guitarist("Тоні Айоммі");
		bassist = new Bassist("Гізер Батлер");
		drummer = new Drummer("Біл Уорд");
	}
	void playCoolSong()
	{
		guitarist->playCoolOpening();
		drummer->startPlaying();
		bassist->followTheDrums();
		guitarist->playCoolRiffs();
		vocalist->singCouplet("1");
		bassist->changeRhythm("приспів");
		guitarist->playAnotherCoolRiffs();
		vocalist->singChorus();
		bassist->changeRhythm("куплет");
		guitarist->playCoolRiffs();
		vocalist->singCouplet("2");
		bassist->changeRhythm("приспів");
		guitarist->playAnotherCoolRiffs();
		vocalist->singChorus();
		bassist->changeRhythm("куплет");
		guitarist->playIncrediblyCoolSolo();
		guitarist->playCoolRiffs();
	}
};
void main()
{
	BlackSabbath* band = new BlackSabbath();
	band->playCoolSong();
}
Приклад реалізації на мові С#
using System;

namespace FacadeExample
{
    // Клас клієнта
    class Client
    {
        static void Main(string[] args)
        {
            //Створюємо екземпляр фасаду - інтерфейс підсистем
            Facade facade = new Facade();

            facade.CallPaired();
            Console.WriteLine("\n\n");
            facade.CallUnpaired();

            Console.ReadKey();
        }
    }

    // Клас фасаду
    class Facade
    {
        Subsystem1 first;
        Subsystem2 second;
        Subsystem3 third;
        Subsystem4 fourth;
        Subsystem5 fifth;

        public Facade()
        {
            this.first = new Subsystem1();
            this.second = new Subsystem2();
            this.third = new Subsystem3();
            this.fourth = new Subsystem4();
            this.fifth = new Subsystem5();
        }

        //Виклик методів з підсистем Subsystem2 та Subsystem4
        public void CallPaired()
        {
            Console.WriteLine("Результати роботи методів підсистем з парним індексом (2,4)\n");
            second.Method();
            fourth.Method();
        }

        //Виклик методів з підсистем Subsystem1, Subsystem3 та Subsystem5
        public void CallUnpaired()
        {
            Console.WriteLine("Результати роботи методів підсистем з непарним індексом (1,3,5)\n");
            first.Method();
            third.Method();
            fifth.Method();
        }
    }

    // Клас підсистеми
    class Subsystem1
    {
        public void Method()
        {
            Console.WriteLine("Метод першої підсистеми");
        }
    }

    // Клас підсистеми
    class Subsystem2
    {
        public void Method()
        {
            Console.WriteLine("Метод другої підсистеми");
        }
    }

    // Клас підсистеми
    class Subsystem3
    {
        public void Method()
        {
            Console.WriteLine("Метод третьої підсистеми");
        }
    }

    // Клас підсистеми
    class Subsystem4
    {
        public void Method()
        {
            Console.WriteLine("Метод четвертої підсистеми");
        }
    }

    // Клас підсистеми
    class Subsystem5
    {
        public void Method()
        {
            Console.WriteLine("Метод п'ятої підсистеми");
        }
    }
}

Джерела

[ред. | ред. код]
  • Gamma, Erich; Helm, Richard; Johnson, Ralph; Vlissides, John (1994). Design Patterns: Elements of Reusable Object-Oriented Software (вид. [1]). Addison–Wesley. с. 395. {{cite book}}: Зовнішнє посилання в |edition= (довідка)(англ.)
  • Alan Shallowey, James R. Trott (2004). Design Patterns Explained: A New Perspective on Object-Oriented Design (PDF).(англ.)
  • www.dofactory.com [Архівовано 29 квітня 2012 у Wayback Machine.]