2.7. Facade¶
2.7.1. Purpose¶
The primary goal of a Facade Pattern is not to avoid you 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 these code on GitHub
Facade.php
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 | <?php
namespace DesignPatterns\Structural\Facade;
/**
*
*
*/
class Facade
{
/**
* @var OsInterface
*/
protected $os;
/**
* @var BiosInterface
*/
protected $bios;
/**
* This is the perfect time to use a dependency injection container
* to create an instance of this class
*
* @param BiosInterface $bios
* @param OsInterface $os
*/
public function __construct(BiosInterface $bios, OsInterface $os)
{
$this->bios = $bios;
$this->os = $os;
}
/**
* turn on the system
*/
public function turnOn()
{
$this->bios->execute();
$this->bios->waitForKeyPress();
$this->bios->launch($this->os);
}
/**
* turn off the system
*/
public function turnOff()
{
$this->os->halt();
$this->bios->powerDown();
}
}
|
OsInterface.php
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | <?php
namespace DesignPatterns\Structural\Facade;
/**
* Class OsInterface
*/
interface OsInterface
{
/**
* halt the OS
*/
public function halt();
}
|
BiosInterface.php
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 | <?php
namespace DesignPatterns\Structural\Facade;
/**
* Class BiosInterface
*/
interface BiosInterface
{
/**
* execute the BIOS
*/
public function execute();
/**
* wait for halt
*/
public function waitForKeyPress();
/**
* launches the OS
*
* @param OsInterface $os
*/
public function launch(OsInterface $os);
/**
* power down BIOS
*/
public function powerDown();
}
|
2.7.4. Test¶
Tests/FacadeTest.php
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 | <?php
namespace DesignPatterns\Structural\Facade\Tests;
use DesignPatterns\Structural\Facade\Facade as Computer;
use DesignPatterns\Structural\Facade\OsInterface;
/**
* FacadeTest shows example of facades
*/
class FacadeTest extends \PHPUnit_Framework_TestCase
{
public function getComputer()
{
$bios = $this->getMockBuilder('DesignPatterns\Structural\Facade\BiosInterface')
->setMethods(array('launch', 'execute', 'waitForKeyPress'))
->disableAutoload()
->getMock();
$operatingSys = $this->getMockBuilder('DesignPatterns\Structural\Facade\OsInterface')
->setMethods(array('getName'))
->disableAutoload()
->getMock();
$bios->expects($this->once())
->method('launch')
->with($operatingSys);
$operatingSys
->expects($this->once())
->method('getName')
->will($this->returnValue('Linux'));
$facade = new Computer($bios, $operatingSys);
return array(array($facade, $operatingSys));
}
/**
* @dataProvider getComputer
*/
public function testComputerOn(Computer $facade, OsInterface $os)
{
// interface is simpler :
$facade->turnOn();
// but I can access to lower component
$this->assertEquals('Linux', $os->getName());
}
}
|