2.7. Facade
2.7.1. Purpose
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.
A Facade is meant to decouple a client and a sub-system by embedding many (but sometimes just one) interface, and of course to reduce complexity.
A facade does not forbid you the access to the sub-system
You can (you should) have multiple facades for one sub-system
That’s why a good facade has no new
in it. If there are multiple
creations for each method, it is not a Facade, it’s a Builder or a
[Abstract|Static|Simple] Factory [Method].
The best facade has no new
and a constructor with
interface-type-hinted parameters. If you need creation of new instances,
use a Factory as argument.
2.7.2. UML Diagram
2.7.3. Code
You can also find this code on 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. Test
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}