Мост (англ. 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() ); } }
-