2.7. Fasada (Facade)

2.7.1. Przeznaczenie

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.

Fasada pozwala oddzielić klienta od podsystemu, poprzez udostępnienie jednego lub wielu interfejsów oraz zredukować złożoność rozwiązania.

  • Fasada nie zabrania bezpośredniego dostępu do podsystemu.

  • Dobrym pomysłem jest posiadanie wielu fasad do jednego podsystemu.

Dlatego dobra fasada nie tworzy nowych obiektów, tylko korzysta z istniejących (nie używa operatora new). Jeżeli w ramach fasady tworzymy wiele obiektów, w ramach każdej metody, wtedy nie mamy do czynienia z Fasadą, tylko z Budowniczym lub formą Fabryki.

W ramach Fasady najlepiej nie używać operatora new oraz definiować typy argumentów konstruktora (type-hinting). Jeżeli potrzebujemy stworzyć nowe obiekty, powinniśmy przekazać Fabrykę jako argument.

2.7.2. Diagram UML

Alt Facade UML Diagram

2.7.3. Kod

Ten kod znajdziesz również na 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. Testy

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}