2.7. Фасад (Facade)

2.7.1. Призначення

The primary goal of a Facade Pattern is not to avoid you having to read the manual of a complex API. It’s only a side-effect. The first goal is to reduce coupling and follow the Law of Demeter.

Фасад призначений для поділу клієнта та підсистеми шляхом впровадження багатьох (але іноді тільки одного) інтерфейсів, і, звичайно, зменшення загальної складності.

  • Фасад не забороняє прямий доступ до підсистеми. Просто він робить його простіше і зрозуміліше.

  • Ви можете (і вам варто) мати кілька фасадів для однієї підсистеми.

Ось чому хороший фасад не містить створення екземплярів класів (new) всередині. Якщо всередині фасаду створюються об’єкти для реалізації кожного методу, це не Фасад, це Будівельник або [Абстрактна|Статична|Проста] Фабрика [або Фабричний Метод].

Кращий фасад не містить new або конструктора з type-hinted параметрами. Якщо вам необхідно створювати нові екземпляри класів, в такому випадку краще використовувати Фабрику як аргумент.

2.7.2. Діаграма UML

Alt Facade UML Diagram

2.7.3. Код

Ви можете знайти цей код на GitHub

Facade.php

 1<?php
 2
 3declare(strict_types=1);
 4
 5namespace DesignPatterns\Structural\Facade;
 6
 7class Facade
 8{
 9    public function __construct(private Bios $bios, private OperatingSystem $os)
10    {
11    }
12
13    public function turnOn()
14    {
15        $this->bios->execute();
16        $this->bios->waitForKeyPress();
17        $this->bios->launch($this->os);
18    }
19
20    public function turnOff()
21    {
22        $this->os->halt();
23        $this->bios->powerDown();
24    }
25}

OperatingSystem.php

 1<?php
 2
 3declare(strict_types=1);
 4
 5namespace DesignPatterns\Structural\Facade;
 6
 7interface OperatingSystem
 8{
 9    public function halt();
10
11    public function getName(): string;
12}

Bios.php

 1<?php
 2
 3declare(strict_types=1);
 4
 5namespace DesignPatterns\Structural\Facade;
 6
 7interface Bios
 8{
 9    public function execute();
10
11    public function waitForKeyPress();
12
13    public function launch(OperatingSystem $os);
14
15    public function powerDown();
16}

2.7.4. Тест

Tests/FacadeTest.php

 1<?php
 2
 3declare(strict_types=1);
 4
 5namespace DesignPatterns\Structural\Facade\Tests;
 6
 7use DesignPatterns\Structural\Facade\Bios;
 8use DesignPatterns\Structural\Facade\Facade;
 9use DesignPatterns\Structural\Facade\OperatingSystem;
10use PHPUnit\Framework\TestCase;
11
12class FacadeTest extends TestCase
13{
14    public function testComputerOn()
15    {
16        $os = $this->createMock(OperatingSystem::class);
17
18        $os->method('getName')
19            ->will($this->returnValue('Linux'));
20
21        $bios = $this->createMock(Bios::class);
22
23        $bios->method('launch')
24            ->with($os);
25
26        /** @noinspection PhpParamsInspection */
27        $facade = new Facade($bios, $os);
28        $facade->turnOn();
29
30        $this->assertSame('Linux', $os->getName());
31    }
32}