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 no new 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

Alt Facade UML Diagram

2.7.3. Code

You can also find this code on GitHub

Facade.php

  1. <?php
  2.  
  3. namespace DesignPatterns\Structural\Facade;
  4.  
  5. class Facade
  6. {
  7. /**
  8. * @var OsInterface
  9. */
  10. private $os;
  11.  
  12. /**
  13. * @var BiosInterface
  14. */
  15. private $bios;
  16.  
  17. /**
  18. * @param BiosInterface $bios
  19. * @param OsInterface $os
  20. */
  21. public function __construct(BiosInterface $bios, OsInterface $os)
  22. {
  23. $this->bios = $bios;
  24. $this->os = $os;
  25. }
  26.  
  27. public function turnOn()
  28. {
  29. $this->bios->execute();
  30. $this->bios->waitForKeyPress();
  31. $this->bios->launch($this->os);
  32. }
  33.  
  34. public function turnOff()
  35. {
  36. $this->os->halt();
  37. $this->bios->powerDown();
  38. }
  39. }

OsInterface.php

  1. <?php
  2.  
  3. namespace DesignPatterns\Structural\Facade;
  4.  
  5. interface OsInterface
  6. {
  7. public function halt();
  8.  
  9. public function getName(): string;
  10. }

BiosInterface.php

  1. <?php
  2.  
  3. namespace DesignPatterns\Structural\Facade;
  4.  
  5. interface BiosInterface
  6. {
  7. public function execute();
  8.  
  9. public function waitForKeyPress();
  10.  
  11. public function launch(OsInterface $os);
  12.  
  13. public function powerDown();
  14. }

2.7.4. Test

Tests/FacadeTest.php

  1. <?php
  2.  
  3. namespace DesignPatterns\Structural\Facade\Tests;
  4.  
  5. use DesignPatterns\Structural\Facade\Facade;
  6. use DesignPatterns\Structural\Facade\OsInterface;
  7. use PHPUnit\Framework\TestCase;
  8.  
  9. class FacadeTest extends TestCase
  10. {
  11. public function testComputerOn()
  12. {
  13. /** @var OsInterface|\PHPUnit_Framework_MockObject_MockObject $os */
  14. $os = $this->createMock('DesignPatterns\Structural\Facade\OsInterface');
  15.  
  16. $os->method('getName')
  17. ->will($this->returnValue('Linux'));
  18.  
  19. $bios = $this->getMockBuilder('DesignPatterns\Structural\Facade\BiosInterface')
  20. ->setMethods(['launch', 'execute', 'waitForKeyPress'])
  21. ->disableAutoload()
  22. ->getMock();
  23.  
  24. $bios->expects($this->once())
  25. ->method('launch')
  26. ->with($os);
  27.  
  28. $facade = new Facade($bios, $os);
  29.  
  30. // the facade interface is simple
  31. $facade->turnOn();
  32.  
  33. // but you can also access the underlying components
  34. $this->assertEquals('Linux', $os->getName());
  35. }
  36. }