2.7. Facade
2.7.1. Purpose
The primary goal of a Facade Pattern is not to avoid you having to read themanual of a complex API. It’s only a side-effect. The first goal is toreduce coupling and follow the Law of Demeter.
A Facade is meant to decouple a client and a sub-system by embeddingmany (but sometimes just one) interface, and of course to reducecomplexity.
- 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 nonew
in it. If there are multiplecreations 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 withinterface-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
- <?php
- namespace DesignPatterns\Structural\Facade;
- class Facade
- {
- /**
- * @var OsInterface
- */
- private $os;
- /**
- * @var BiosInterface
- */
- private $bios;
- /**
- * @param BiosInterface $bios
- * @param OsInterface $os
- */
- public function __construct(BiosInterface $bios, OsInterface $os)
- {
- $this->bios = $bios;
- $this->os = $os;
- }
- public function turnOn()
- {
- $this->bios->execute();
- $this->bios->waitForKeyPress();
- $this->bios->launch($this->os);
- }
- public function turnOff()
- {
- $this->os->halt();
- $this->bios->powerDown();
- }
- }
OsInterface.php
- <?php
- namespace DesignPatterns\Structural\Facade;
- interface OsInterface
- {
- public function halt();
- public function getName(): string;
- }
BiosInterface.php
- <?php
- namespace DesignPatterns\Structural\Facade;
- interface BiosInterface
- {
- public function execute();
- public function waitForKeyPress();
- public function launch(OsInterface $os);
- public function powerDown();
- }
2.7.4. Test
Tests/FacadeTest.php
- <?php
- namespace DesignPatterns\Structural\Facade\Tests;
- use DesignPatterns\Structural\Facade\Facade;
- use DesignPatterns\Structural\Facade\OsInterface;
- use PHPUnit\Framework\TestCase;
- class FacadeTest extends TestCase
- {
- public function testComputerOn()
- {
- /** @var OsInterface|\PHPUnit_Framework_MockObject_MockObject $os */
- $os = $this->createMock('DesignPatterns\Structural\Facade\OsInterface');
- $os->method('getName')
- ->will($this->returnValue('Linux'));
- $bios = $this->getMockBuilder('DesignPatterns\Structural\Facade\BiosInterface')
- ->setMethods(['launch', 'execute', 'waitForKeyPress'])
- ->disableAutoload()
- ->getMock();
- $bios->expects($this->once())
- ->method('launch')
- ->with($os);
- $facade = new Facade($bios, $os);
- // the facade interface is simple
- $facade->turnOn();
- // but you can also access the underlying components
- $this->assertEquals('Linux', $os->getName());
- }
- }