Мост (англ. Bridge ) — структурный шаблон проектирования, используемый в проектировании программного обеспечения
чтобы “разделять абстракцию и реализацию так, чтобы они могли изменяться независимо”. Шаблон мост использует
инкапсуляцию, агрегирование и может использовать наследование для того, чтобы разделить ответственность между классами.
Родственным шаблоном для Моста является шаблон Адаптер , который объединяет связанные части системы и предоставляет
простой интерфейс.
У нас есть филиалы в штатах и Европе. У каждого из регионов разная валюта. И подсчёты прибыли тоже производятся
по-разному. Но наши CashBox
всегда должны быть CashBox
. Это и есть абстракция.
Некоторые методы нашей абстракции, зависят от аргумента, который передаётся. Тип указан интерфейс CurrencyInterface
.
Интерфейс и есть реализация. Нам не нужно каждый раз наследовать родителя и менять что-то. У нас есть один тип, и мы знаем,
как с ним работать. Как мы видим, что данный шаблон мы уже встречали в наших примерах.
Abstraction
AbstractCashBox.php
<?php
namespace DesignPatterns\Structural\Bridge\Abstraction ;
use DesignPatterns\Structural\Bridge\Implementation\CurrencyInterface ;
/**
* Class AbstractCashBox
* @package DesignPatterns\Structural\Bridge\Abstraction
*/
abstract class AbstractCashBox
{
/**
* @var CurrencyInterface
*/
protected $defaultCurrency ;
/**
* @var CurrencyInterface[]|float
*/
protected $cash = [];
/**
* AbstractCashBox constructor.
*
* @param CurrencyInterface $currency
*/
public function __construct ( CurrencyInterface $currency )
{
$this -> defaultCurrency = $currency ;
}
/**
* @return CurrencyInterface
*/
public function getDefaultCurrency (): CurrencyInterface
{
return $this -> defaultCurrency ;
}
/**
* @return float
*/
abstract public function getCashInCashBox (): float ;
/**
* @param CurrencyInterface $currency
*
* @return void
*/
abstract public function setCash ( CurrencyInterface $currency );
}
EuropeCashBox.php
<?php
namespace DesignPatterns\Structural\Bridge\Abstraction ;
use DesignPatterns\Structural\Bridge\Implementation\CurrencyInterface ;
/**
* Class EuropeCashBox
* @package DesignPatterns\Structural\Bridge\Abstraction
*/
class EuropeCashBox extends AbstractCashBox
{
/**
* @return float
*/
public function getCashInCashBox (): float
{
return array_sum ( $this -> cash );
}
/**
* @param CurrencyInterface $currency
*
* @return void
*/
public function setCash ( CurrencyInterface $currency )
{
$defaultCurrencyRate = $this -> defaultCurrency -> getCurrencyRate ();
array_push ( $this -> cash , ( $currency -> getSum () * $defaultCurrencyRate ) / $currency -> getCurrencyRate ());
}
}
UsaCashBox.php
<?php
namespace DesignPatterns\Structural\Bridge\Abstraction ;
use DesignPatterns\Structural\Bridge\Implementation\CurrencyInterface ;
/**
* Class UsaCashBox
* @package DesignPatterns\Structural\Bridge\Abstraction
*/
class UsaCashBox extends AbstractCashBox
{
/**
* @return float
*/
public function getCashInCashBox (): float
{
$result = 0.0 ;
$defaultCurrencyRate = $this -> defaultCurrency -> getCurrencyRate ();
foreach ( $this -> cash as $cash ) {
$result += ( $cash -> getSum () * $defaultCurrencyRate ) / $cash -> getCurrencyRate ();
}
return $result ;
}
/**
* @param CurrencyInterface $currency
*
* @return void
*/
public function setCash ( CurrencyInterface $currency )
{
array_push ( $this -> cash , $currency );
}
}
Implementation
AbstractCurrency.php
<?php
namespace DesignPatterns\Structural\Bridge\Implementation ;
/**
* Class AbstractCurrency
* @package DesignPatterns\Structural\Bridge\Implementation
*/
abstract class AbstractCurrency implements CurrencyInterface
{
/**
* @var string
*/
protected $symbol ;
/**
* @var float
*/
protected $sumCash = 0.0 ;
/**
* AbstractCurrency constructor.
*
* @param float $sumCash
*/
public function __construct ( float $sumCash = null )
{
if ( $sumCash ) {
$this -> sumCash = $sumCash ;
}
}
/**
* @return string
*/
public function getCurrencySymbol (): string
{
return $this -> symbol ;
}
/**
* @return float
*/
public function getCurrencyRate (): float
{
return static :: CURRENCY_RATE ;
}
/**
* @return float
*/
public function getSum (): float
{
return $this -> sumCash ;
}
}
CurrencyInterface.php
<?php
namespace DesignPatterns\Structural\Bridge\Implementation ;
/**
* Interface CurrencyInterface
* @package DesignPatterns\Structural\Bridge\Implementation
*/
interface CurrencyInterface
{
/**
* CurrencyInterface constructor.
*
* @param float $sumCash
*/
public function __construct ( float $sumCash );
/**
* @return string
*/
public function getCurrencySymbol (): string ;
/**
* @return float
*/
public function getCurrencyRate (): float ;
/**
* @return float
*/
public function getSum (): float ;
}
DollarCurrency.php
<?php
namespace DesignPatterns\Structural\Bridge\Implementation ;
/**
* Class DollarCurrency
* @package DesignPatterns\Structural\Bridge\Implementation
*/
class DollarCurrency extends AbstractCurrency
{
/**
* @var string
*/
protected $symbol = '$' ;
/**
* @var float
*/
const CURRENCY_RATE = 2.0 ;
}
EuroCurrency.php
<?php
namespace DesignPatterns\Structural\Bridge\Implementation ;
/**
* Class EuroCurrency
* @package DesignPatterns\Structural\Bridge\Implementation
*/
class EuroCurrency extends AbstractCurrency
{
/**
* @var string
*/
protected $symbol = '€' ;
/**
* @var float
*/
const CURRENCY_RATE = 1 ;
}
Test case:
BridgeTest.php
<?php
namespace DesignPatterns\Tests\Structural\Bridge ;
use DesignPatterns\Structural\Bridge\Abstraction\EuropeCashBox ;
use DesignPatterns\Structural\Bridge\Abstraction\UsaCashBox ;
use DesignPatterns\Structural\Bridge\Implementation\CurrencyInterface ;
use DesignPatterns\Structural\Bridge\Implementation\DollarCurrency ;
use DesignPatterns\Structural\Bridge\Implementation\EuroCurrency ;
use PHPUnit_Framework_TestCase ;
class BridgeTest extends PHPUnit_Framework_TestCase
{
public function testDollarCurrencyInstanceOfCurrencyInterface ()
{
$dollar = new DollarCurrency ();
$this -> assertInstanceOf ( 'DesignPatterns\Structural\Bridge\Implementation\CurrencyInterface' , $dollar );
return $dollar ;
}
/**
* @depends testDollarCurrencyInstanceOfCurrencyInterface
*
* @param CurrencyInterface $dollar
*/
public function testDollarGetSymbol ( CurrencyInterface $dollar )
{
$this -> assertEquals ( '$' , $dollar -> getCurrencySymbol ());
}
/**
* @depends testDollarCurrencyInstanceOfCurrencyInterface
*
* @param CurrencyInterface $dollar
*/
public function testDollarGetRate ( CurrencyInterface $dollar )
{
$this -> assertEquals ( DollarCurrency :: CURRENCY_RATE , $dollar -> getCurrencyRate ());
}
public function testDollarGetSum ()
{
$val = 234.24 ;
$dollar = new DollarCurrency ( $val );
$this -> assertEquals ( $val , $dollar -> getSum ());
}
public function testEuroCurrencyInstanceOfCurrencyInterface ()
{
$euro = new EuroCurrency ();
$this -> assertInstanceOf ( 'DesignPatterns\Structural\Bridge\Implementation\CurrencyInterface' , $euro );
return $euro ;
}
/**
* @depends testEuroCurrencyInstanceOfCurrencyInterface
*
* @param CurrencyInterface $euro
*/
public function testEuroGetSymbol ( CurrencyInterface $euro )
{
$this -> assertEquals ( '€' , $euro -> getCurrencySymbol ());
}
/**
* @depends testEuroCurrencyInstanceOfCurrencyInterface
*
* @param CurrencyInterface $euro
*/
public function testEuroGetRate ( CurrencyInterface $euro )
{
$this -> assertEquals ( EuroCurrency :: CURRENCY_RATE , $euro -> getCurrencyRate ());
}
public function testEuroGetSum ()
{
$val = 2555.24 ;
$dollar = new EuroCurrency ( $val );
$this -> assertEquals ( $val , $dollar -> getSum ());
}
public function testUsaCashBoxInstanceOfAbstractCashBox ()
{
$dollar = new DollarCurrency ();
$usaCashBox = new UsaCashBox ( $dollar );
$this -> assertInstanceOf ( 'DesignPatterns\Structural\Bridge\Abstraction\AbstractCashBox' , $usaCashBox );
}
public function testEuroCashBoxInstanceOfAbstractCashBox ()
{
$euro = new EuroCurrency ();
$euroCashBox = new EuropeCashBox ( $euro );
$this -> assertInstanceOf ( 'DesignPatterns\Structural\Bridge\Abstraction\AbstractCashBox' , $euroCashBox );
}
public function testUsaCashBoxGetCashInCashBox ()
{
$dollar = new DollarCurrency ();
$fiveDollars = new DollarCurrency ( 5 );
$sixDollars = new DollarCurrency ( 6 );
$tenEuros = new EuroCurrency ( 10 );
$usaCashBox = new UsaCashBox ( $dollar );
$usaCashBox -> setCash ( $fiveDollars );
$this -> assertEquals ( $fiveDollars -> getSum (), $usaCashBox -> getCashInCashBox ());
$usaCashBox -> setCash ( $sixDollars );
$this -> assertEquals (
$fiveDollars -> getSum () + $sixDollars -> getSum (),
$usaCashBox -> getCashInCashBox ()
);
$usaCashBox -> setCash ( $tenEuros );
$defaultCurrencyRate = $usaCashBox -> getDefaultCurrency () -> getCurrencyRate ();
$this -> assertEquals (
$fiveDollars -> getSum ()
+ $sixDollars -> getSum ()
+ (( $tenEuros -> getSum () * $defaultCurrencyRate ) / $tenEuros -> getCurrencyRate ()),
$usaCashBox -> getCashInCashBox ()
);
}
}