Фасад (шаблон проектирования): различия между версиями
Dzmuh (обсуждение | вклад) (→Ссылки) |
Dzmuh (обсуждение | вклад) |
||
| (не показаны 4 промежуточные версии этого же участника) | |||
| Строка 33: | Строка 33: | ||
| title = Исходный текст на языке [[C++]] | | title = Исходный текст на языке [[C++]] | ||
| content = | | content = | ||
< | <syntaxhighlight lang="cpp"> | ||
#include <iostream> | #include <iostream> | ||
| Строка 218: | Строка 218: | ||
* Тони Айомми заканчивает песню мощным аккордом. | * Тони Айомми заканчивает песню мощным аккордом. | ||
*/ | */ | ||
</ | </syntaxhighlight> | ||
}} | }} | ||
| Строка 225: | Строка 225: | ||
| title = Исходный текст на языке [[JavaScript]] | | title = Исходный текст на языке [[JavaScript]] | ||
| content = | | content = | ||
< | <syntaxhighlight lang="javascript"> | ||
/* Complex parts */ | /* Complex parts */ | ||
function SubSystem1() { | function SubSystem1() { | ||
| Строка 274: | Строка 274: | ||
"вызван SubSystem2.methodB" | "вызван SubSystem2.methodB" | ||
*/ | */ | ||
</ | </syntaxhighlight> | ||
}} | }} | ||
=== PHP === | === PHP === | ||
{{Hider_hiding | {{Hider_hiding | ||
| title = Исходный текст на языке [[PHP]] | | title = Исходный текст на языке [[PHP]] | ||
| content = | | content = | ||
< | <syntaxhighlight lang="php"> | ||
/** | /** | ||
* Реализации отдельных частей компьютера. | * Реализации отдельных частей компьютера. | ||
| Строка 362: | Строка 363: | ||
$computer = new Computer(); | $computer = new Computer(); | ||
$computer->startComputer(); | $computer->startComputer(); | ||
</ | </syntaxhighlight> | ||
}} | }} | ||
=== Python === | === Python === | ||
{{Hider_hiding | {{Hider_hiding | ||
| title = Исходный текст на языке [[Python]] | | title = Исходный текст на языке [[Python]] | ||
| content = | | content = | ||
< | <syntaxhighlight lang="python"> | ||
# Сложные части системы | # Сложные части системы | ||
class CPU(object): | class CPU(object): | ||
| Строка 422: | Строка 424: | ||
facade = Computer() | facade = Computer() | ||
facade.startComputer() | facade.startComputer() | ||
</ | </syntaxhighlight> | ||
}} | }} | ||
=== C# === | === C# === | ||
{{Hider_hiding | {{Hider_hiding | ||
| title = Исходный текст на языке [[C Sharp|C#]] | | title = Исходный текст на языке [[C Sharp|C#]] | ||
| content = | | content = | ||
< | <syntaxhighlight lang="csharp"> | ||
using System; | using System; | ||
| Строка 513: | Строка 516: | ||
} | } | ||
} | } | ||
</ | </syntaxhighlight> | ||
}} | }} | ||
== Литература == | == Литература == | ||
* {{книга | * {{книга | ||
Текущая версия от 00:07, 11 июня 2023
| Фасад | |
|---|---|
| Facade | |
| Ошибка Lua в Модуль:Wikidata на строке 288: attempt to index field 'wikibase' (a nil value). | |
| Тип | структурный |
| Описан в Design Patterns | Да |
Шаблон фасад (англ. Facade) — структурный шаблон проектирования, позволяющий скрыть сложность системы путём сведения всех возможных внешних вызовов к одному объекту, делегирующему их соответствующим объектам системы.
Описание
Проблема
Как обеспечить унифицированный интерфейс с набором разрозненных реализаций или интерфейсов, например, с подсистемой, если нежелательно сильное связывание с этой подсистемой или реализация подсистемы может измениться?
Решение
Определить одну точку взаимодействия с подсистемой — фасадный объект, обеспечивающий общий интерфейс с подсистемой, и возложить на него обязанность по взаимодействию с её компонентами. Фасад — это внешний объект, обеспечивающий единственную точку входа для служб подсистемы. Реализация других компонентов подсистемы закрыта и не видна внешним компонентам. Фасадный объект обеспечивает реализацию GRASP паттерна Устойчивый к изменениям (Protected Variations) с точки зрения защиты от изменений в реализации подсистемы.
Особенности применения
Шаблон применяется для установки некоторого рода политики по отношению к другой группе объектов. Если политика должна быть яркой и заметной, следует воспользоваться услугами шаблона Фасад. Если же необходимо обеспечить скрытность и аккуратность (прозрачность), более подходящим выбором является шаблон Заместитель (Proxy).
Примеры
C++
#include <iostream>
#include <string>
#include <memory>
#include <string_view>
/** Абстрактный музыкант - не является обязательной составляющей паттерна, введен для упрощения кода */
class Musician {
const char* name;
public:
Musician(std::string_view name) {
this->name = name.data();
}
virtual ~Musician() =default;
protected:
void output(std::string_view text) {
std::cout << this->name << " " << text << "." << std::endl;
}
};
/** Конкретные музыканты */
class Vocalist: public Musician {
public:
Vocalist(std::string_view name): Musician(name) {}
void singCouplet(int coupletNumber) {
std::string text = "спел куплет №";
text += std::to_string(coupletNumber);
output(text);
}
void singChorus() {
output("спел припев");
}
};
class Guitarist: public Musician {
public:
Guitarist(std::string_view name): Musician(name) {}
void playCoolOpening() {
output("начинает с крутого вступления");
}
void playCoolRiffs() {
output("играет крутые риффы");
}
void playAnotherCoolRiffs() {
output("играет другие крутые риффы");
}
void playIncrediblyCoolSolo() {
output("выдает невероятно крутое соло");
}
void playFinalAccord() {
output("заканчивает песню мощным аккордом");
}
};
class Bassist: public Musician {
public:
Bassist(std::string_view name): Musician(name) {}
void followTheDrums() {
output("следует за барабанами");
}
void changeRhythm(std::string_view type) {
std::string text = ("перешел на ритм ");
text += type;
text += "a";
output(text);
}
void stopPlaying() {
output("заканчивает играть");
}
};
class Drummer: public Musician {
public:
Drummer(std::string_view name): Musician(name) {}
void startPlaying() {
output("начинает играть");
}
void stopPlaying() {
output("заканчивает играть");
}
};
/** Фасад, в данном случае - знаменитая рок-группа */
class BlackSabbath {
std::unique_ptr<Vocalist> vocalist;
std::unique_ptr<Guitarist> guitarist;
std::unique_ptr<Bassist> bassist;
std::unique_ptr<Drummer> drummer;
public:
BlackSabbath() {
vocalist = std::make_unique<Vocalist>("Оззи Осборн");
guitarist = std::make_unique<Guitarist>("Тони Айомми");
bassist = std::make_unique<Bassist>("Гизер Батлер");
drummer = std::make_unique<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();
vocalist->singCouplet(3);
bassist->changeRhythm("припев");
guitarist->playAnotherCoolRiffs();
vocalist->singChorus();
bassist->changeRhythm("куплет");
guitarist->playCoolRiffs();
bassist->stopPlaying();
drummer->stopPlaying();
guitarist->playFinalAccord();
}
};
int main() {
std::cout << "OUTPUT:" << std::endl;
BlackSabbath band;
band.playCoolSong();
return 0;
}
/**
* OUTPUT:
* Тони Айомми начинает с крутого вступления.
* Билл Уорд начинает играть.
* Гизер Батлер следует за барабанами.
* Тони Айомми играет крутые риффы.
* Оззи Осборн спел куплет №1.
* Гизер Батлер перешел на ритм припевa.
* Тони Айомми играет другие крутые риффы.
* Оззи Осборн спел припев.
* Гизер Батлер перешел на ритм куплетa.
* Тони Айомми играет крутые риффы.
* Оззи Осборн спел куплет №2.
* Гизер Батлер перешел на ритм припевa.
* Тони Айомми играет другие крутые риффы.
* Оззи Осборн спел припев.
* Гизер Батлер перешел на ритм куплетa.
* Тони Айомми выдает невероятно крутое соло.
* Тони Айомми играет крутые риффы.
* Оззи Осборн спел куплет №3.
* Гизер Батлер перешел на ритм припевa.
* Тони Айомми играет другие крутые риффы.
* Оззи Осборн спел припев.
* Гизер Батлер перешел на ритм куплетa.
* Тони Айомми играет крутые риффы.
* Гизер Батлер заканчивает играть.
* Билл Уорд заканчивает играть.
* Тони Айомми заканчивает песню мощным аккордом.
*/
JavaScript
/* Complex parts */
function SubSystem1() {
this.method1 = function() {
console.log("вызван SubSystem1.method1");
};
}
function SubSystem2() {
this.method2 = function() {
console.log("вызван SubSystem2.method2");
};
this.methodB = function() {
console.log("вызван SubSystem2.methodB");
};
}
/* Facade */
function Facade() {
var s1 = new SubSystem1(),
s2 = new SubSystem2();
this.m1 = function() {
console.log("вызван Facade.m1");
s1.method1();
s2.method2();
};
this.m2 = function() {
console.log("вызван Facade.m2");
s2.methodB();
};
}
/* Client */
function test() {
var facade = new Facade();
facade.m1();
facade.m2();
}
test();
/*
Выведет:
"вызван Facade.m1"
"вызван SubSystem1.method1"
"вызван SubSystem2.method2"
"вызван Facade.m2"
"вызван SubSystem2.methodB"
*/
PHP
/**
* Реализации отдельных частей компьютера.
* У каждого метода классов имеется какая-то реализация, в данном примере она опущена.
*/
/**
* Class CPU, отвечает за работу процессора
*/
class CPU
{
public function freeze() {}
public function jump($position) {}
public function execute() {}
}
/**
* Class Memory, отвечает за работу памяти
*/
class Memory
{
const BOOT_ADDRESS = 0x0005;
public function load($position, $data) {}
}
/**
* Class HardDrive, отвечает за работу жёсткого диска
*/
class HardDrive
{
const BOOT_SECTOR = 0x001;
const SECTOR_SIZE = 64;
public function read($lba, $size) {}
}
/**
* Пример шаблона "Фасад"
* В качестве унифицированного объекта выступает Компьютер.
* За этим объектом будут скрыты все детали работы его внутренних частей.
*/
class Computer
{
protected $cpu;
protected $memory;
protected $hardDrive;
/**
* Computer constructor.
* Инициализируем части
*/
public function __construct()
{
$this->cpu = new CPU();
$this->memory = new Memory();
$this->hardDrive = new HardDrive();
}
/**
* Упрощённая обработка поведения "запуск компьютера"
*/
public function startComputer()
{
$cpu = $this->cpu;
$memory = $this->memory;
$hardDrive = $this->hardDrive;
$cpu->freeze();
$memory->load(
$memory::BOOT_ADDRESS,
$hardDrive->read($hardDrive::BOOT_SECTOR, $hardDrive::SECTOR_SIZE)
);
$cpu->jump($memory::BOOT_ADDRESS);
$cpu->execute();
}
}
/**
* Пользователям компьютера предоставляется Фасад (компьютер),
* который скрывает все сложность работы с отдельными компонентами.
*/
$computer = new Computer();
$computer->startComputer();
Python
# Сложные части системы
class CPU(object):
def __init__(self):
# ...
pass
def freeze(self):
# ...
pass
def jump(self, address):
# ...
pass
def execute(self):
# ...
pass
class Memory(object):
def __init__(self):
# ...
pass
def load(self, position, data):
# ...
pass
class HardDrive(object):
def __init__(self):
# ...
pass
def read(self, lba, size):
# ...
pass
# Фасад
class Computer(object):
def __init__(self):
self._cpu = CPU()
self._memory = Memory()
self._hardDrive = HardDrive()
def startComputer(self):
self._cpu.freeze()
self._memory.load(BOOT_ADDRESS, self._hardDrive.read(BOOT_SECTOR, SECTOR_SIZE))
self._cpu.jump(BOOT_ADDRESS)
self._cpu.execute()
# Клиентская часть
if __name__ == "__main__":
facade = Computer()
facade.startComputer()
C#
using System;
namespace Library
{
/// <summary>
/// Класс подсистемы
/// </summary>
/// <remarks>
/// <li>
/// <lu>реализует функциональность подсистемы;</lu>
/// <lu>выполняет работу, порученную объектом <see cref="Facade"/>;</lu>
/// <lu>ничего не "знает" о существовании фасада, то есть не хранит ссылок на него;</lu>
/// </li>
/// </remarks>
internal class SubsystemA
{
internal string A1()
{
return "Subsystem A, Method A1\n";
}
internal string A2()
{
return "Subsystem A, Method A2\n";
}
}
internal class SubsystemB
{
internal string B1()
{
return "Subsystem B, Method B1\n";
}
}
internal class SubsystemC
{
internal string C1()
{
return "Subsystem C, Method C1\n";
}
}
}
/// <summary>
/// Facade - фасад
/// </summary>
/// <remarks>
/// <li>
/// <lu>"знает", каким классами подсистемы адресовать запрос;</lu>
/// <lu>делегирует запросы клиентов подходящим объектам внутри подсистемы;</lu>
/// </li>
/// </remarks>
public class Facade
{
Library.SubsystemA a = new Library.SubsystemA();
Library.SubsystemB b = new Library.SubsystemB();
Library.SubsystemC c = new Library.SubsystemC();
public void Operation1()
{
Console.WriteLine("Operation 1\n" +
a.A1() +
a.A2() +
b.B1());
}
public void Operation2()
{
Console.WriteLine("Operation 2\n" +
b.B1() +
c.C1());
}
}
class Program
{
static void Main(string[] args)
{
Facade facade = new Facade();
facade.Operation1();
facade.Operation2();
// Wait for user
Console.Read();
}
}
Литература
- Э. Гамма, Р. Хелм, Р. Джонсон, Дж. Влиссидес. Приемы объектно-ориентированного проектирования. Паттерны проектирования = Design Patterns: Elements of Reusable Object-Oriented Software. — Шаблон:Указание места в библиоссылке: «Питер», 2007. — С. 366. — ISBN 978-5-469-01136-1. (также ISBN 5-272-00355-1)
Ссылки
- Паттерн Facade (фасад) — назначение, описание, особенности и реализация на C++.
- Паттерны для масштабируемых JavaScript-приложений. Глава 9. Паттерн «Фасад» — описание, пример реализации.