Фасад (англ. Facade ) - относиться к классу структурных шаблонов. Представляет собой унифицированный интерфейс вместо
набора интерфейсов некоторой подсистемы.
Фасад предназначен для разделения клиента и подсистемы. Фасад не запрещает прямой доступ к подсистеме.
Он делает его проще и понятнее.
Сам шаблон очень похож на Строитель . Не стоит забывать, что Строитель порождающий, а Фасад - структурный.
Когда наш клиент делает заказ, он не хочет знать что, где, когда происходит. Он просто делает заказ у кассира(CashMan
).
А кассир уже знает, что делать с этими данными, и с какими частями системы взаимодействовать для достижения результата.
BurgerWorker.php
<?php
namespace DesignPatterns\Structural\Facade ;
/**
* Class BurgerWorker
* @package DesignPatterns\Structural\Facade
*/
class BurgerWorker
{
/**
* @var array
*/
protected $burgers = [
'hamburger' => [
'muffin' => 'muffin' ,
'meat' => 'beef' ,
'sauce' => 'ketchup' ,
'withCheese' => false ,
],
'cheeseburger' => [
'muffin' => 'muffin' ,
'meat' => 'chicken' ,
'sauce' => 'mayonnaise' ,
'withCheese' => true ,
],
];
/**
* @var array
*/
protected $prices = [
'hamburger' => 12.5 ,
'cheeseburger' => 14.25 ,
];
/**
* @param string $burgerName
*
* @return array
*/
public function make ( string $burgerName ): array
{
return $this -> burgers [ $burgerName ];
}
/**
* @param string $burgerName
*
* @return float
*/
public function getPrice ( string $burgerName ): float
{
return $this -> prices [ $burgerName ];
}
}
CashBox.php
<?php
namespace DesignPatterns\Structural\Facade ;
use Exception ;
/**
* Class CashBox
* @package DesignPatterns\Structural\Facade
*/
class CashBox
{
/**
* @var float
*/
protected $cash ;
/**
* CashBox constructor.
*
* @param float $cash
*/
public function __construct ( float $cash )
{
$this -> cash = $cash ;
}
/**
* @return float
*/
public function getCash (): float
{
return $this -> cash ;
}
/**
* @param $orderPrice
* @param $cash
*
* @return float
* @throws Exception
*/
public function makeOrder ( $orderPrice , $cash ): float
{
$change = $cash - $orderPrice ;
if ( $change < 0 ) {
throw new Exception ( 'Need more money.' );
}
$this -> cash += $cash - $change ;
return $change ;
}
}
CashMan.php
<?php
namespace DesignPatterns\Structural\Facade ;
use InvalidArgumentException ;
/**
* Class CashMan
* @package DesignPatterns\Structural\Facade
*/
class CashMan
{
/**
* @var BurgerWorker
*/
protected $burgerWorker ;
/**
* @var WaterWorker
*/
protected $waterWorker ;
/**
* @var CashBox
*/
protected $cashBox ;
/**
* @var array
*/
protected $order = [];
/**
* @var float
*/
protected $orderPrice = 0.0 ;
/**
* CashMan constructor.
*
* @param BurgerWorker $burgerWorker
* @param WaterWorker $waterWorker
* @param CashBox $cashBox
*/
public function __construct ( BurgerWorker $burgerWorker , WaterWorker $waterWorker , CashBox $cashBox )
{
$this -> burgerWorker = $burgerWorker ;
$this -> waterWorker = $waterWorker ;
$this -> cashBox = $cashBox ;
}
/**
* @param array $order
* @param $cash
*
* @return array
*/
public function makeOrder ( array $order , $cash )
{
if ( ! array_key_exists ( 'waters' , $order ) && ! array_key_exists ( 'burgers' , $order )) {
throw new InvalidArgumentException ();
}
if ( array_key_exists ( 'waters' , $order )) {
$this -> setProductsToOrderWithPrice ( $this -> waterWorker , $order [ 'waters' ]);
}
if ( array_key_exists ( 'burgers' , $order )) {
$this -> setProductsToOrderWithPrice ( $this -> burgerWorker , $order [ 'burgers' ]);
}
$change = $this -> cashBox -> makeOrder ( $this -> orderPrice , $cash );
$fullOrder = [
'order' => $this -> order ,
'price' => $this -> orderPrice ,
'change' => $change ,
];
$this -> resetResult ();
return $fullOrder ;
}
/**
* @param WaterWorker|BurgerWorker $worker
* @param array|string $products
*
* @return void
*/
protected function setProductsToOrderWithPrice ( $worker , $products )
{
if ( is_array ( $products )) {
foreach ( $products as $product ) {
$this -> setProductAndPrice ( $worker , $product );
}
} else {
$this -> setProductAndPrice ( $worker , $products );
}
}
/**
* @param WaterWorker|BurgerWorker $worker
* @param string $product
*
* @return void
*/
protected function setProductAndPrice ( $worker , $product )
{
$this -> order [] = $worker -> make ( $product );
$this -> orderPrice += $worker -> getPrice ( $product );
}
/**
* @return void
*/
protected function resetResult ()
{
$this -> orderPrice = 0 ;
$this -> order = [];
}
}
WaterWorker.php
<?php
namespace DesignPatterns\Structural\Facade ;
/**
* Class WaterWorker
* @package DesignPatterns\Structural\Facade
*/
class WaterWorker
{
/**
* @var array
*/
protected $waters = [
'cocaCola' => 'Coca-Cola' ,
'fanta' => 'Fanta' ,
'sprite' => 'Sprite' ,
];
/**
* @var array
*/
protected $prices = [
'cocaCola' => 2 ,
'fanta' => 3 ,
'sprite' => 1 ,
];
/**
* @param string $waterName
*
* @return string
*/
public function make ( string $waterName ): string
{
return $this -> waters [ $waterName ];
}
/**
* @param string $waterName
*
* @return float
*/
public function getPrice ( string $waterName ): float
{
return $this -> prices [ $waterName ];
}
}
Test case:
FacadeTest.php
<?php
namespace DesignPatterns\Structural\Facade ;
class FacadeTest extends \ PHPUnit_Framework_TestCase
{
const MONEY_IN_CASH_BOX = 1000 ;
protected $firstOrder = [
'burgers' => 'hamburger' ,
'waters' => 'fanta' ,
'cash' => 30 ,
];
protected $secondOrder = [
'burgers' => [
'hamburger' ,
'cheeseburger' ,
],
'waters' => 'cocaCola' ,
'cash' => 50 ,
];
/**
* @var CashBox
*/
protected $cashBox ;
/**
* @var CashMan
*/
protected $cashMan ;
/**
* @var BurgerWorker
*/
protected $burgerWorker ;
/**
* @var WaterWorker
*/
protected $waterWorker ;
public function setUp (): void
{
$this -> cashBox = new CashBox ( self :: MONEY_IN_CASH_BOX );
$this -> burgerWorker = new BurgerWorker ();
$this -> waterWorker = new WaterWorker ();
$this -> cashMan = new CashMan (
$this -> burgerWorker ,
$this -> waterWorker ,
$this -> cashBox
);
}
public function testMakeFirstOrder ()
{
$this -> assertEquals ( $this -> cashBox -> getCash (), self :: MONEY_IN_CASH_BOX );
$firstOrder = $this -> cashMan -> makeOrder ( $this -> firstOrder , $this -> firstOrder [ 'cash' ]);
$this -> assertIsArray ( $firstOrder );
$this -> assertArrayHasKey ( 'price' , $firstOrder );
$this -> assertArrayHasKey ( 'change' , $firstOrder );
$this -> assertEquals ( $firstOrder [ 'change' ], $this -> firstOrder [ 'cash' ] - $firstOrder [ 'price' ]);
$this -> assertEquals ( $this -> cashBox -> getCash (), self :: MONEY_IN_CASH_BOX + $firstOrder [ 'price' ]);
return $firstOrder ;
}
public function testMakeSecondOrder ()
{
$secondOrder = $this -> cashMan -> makeOrder ( $this -> secondOrder , $this -> secondOrder [ 'cash' ]);
$this -> assertIsArray ( $secondOrder );
$this -> assertArrayHasKey ( 'price' , $secondOrder );
$this -> assertArrayHasKey ( 'change' , $secondOrder );
$this -> assertEquals ( $secondOrder [ 'change' ], $this -> secondOrder [ 'cash' ] - $secondOrder [ 'price' ]);
$this -> assertEquals (
$this -> cashBox -> getCash (),
self :: MONEY_IN_CASH_BOX + $secondOrder [ 'price' ]
);
}
}