Адаптер (англ. Adapter) - структурный шаблон проектирования, предназначенный для организации использования функций
объекта, недоступного для модификации, через специально созданный интерфейс.
Позволяет привести нестандартный или неудобный интерфейс какого-то класса в интерфейс, совместимый с вашим кодом. Адаптер позволяет классам работать вместе стандартным образом, что обычно не получается, из-за несовместимых интерфейсов, предоставляя для этого прослойку с интерфейсом, удобным для клиентов, самостоятельно используя оригинальный интерфейс.
У нас есть класс CashBox
. CashBox->setCash()
принимает только объекты типа DollarInterface
.
Представим что у нас нескольких закусочных в разных уголках мира. В каждом из них своя валюта. А наш метод умеет работать
только с долларами. Плюс для правильного подсчёта нам необходимо конвертировать валюту. Что бы привести, всё к одному виду
нам и нужен Адаптер.
-
Dollar
-
DollarInterface.php
<?php namespace DesignPatterns\Structural\Adapter\Dollar; /** * Interface DollarInterface * @package DesignPatterns\Structural\Adapter\Dollar */ interface DollarInterface { /** * @return float */ public function getCash(): float; }
-
DollarsCash.php
<?php namespace DesignPatterns\Structural\Adapter\Dollar; /** * Class DollarsCash * @package DesignPatterns\Structural\Adapter\Dollar */ class DollarsCash implements DollarInterface { /** * @var float */ protected $cash; /** * DollarsCash constructor. * * @param float $cash */ public function __construct(float $cash) { $this->cash = $cash; } /** * @return float */ public function getCash(): float { return $this->cash; } }
-
-
Euro
-
EuroCash.php
<?php namespace DesignPatterns\Structural\Adapter\Euro; /** * Class EuroCash * @package DesignPatterns\Structural\Adapter\Euro */ class EuroCash implements EuroInterface { /** * @var float */ protected $cash; /** * EuroCash constructor. * * @param float $cash */ public function __construct(float $cash) { $this->cash = $cash; } /** * @return float */ public function getCash(): float { return $this->cash; } }
-
EuroInterface.php
<?php namespace DesignPatterns\Structural\Adapter\Euro; /** * Interface EuroInterface * @package DesignPatterns\Structural\Adapter\Euro */ interface EuroInterface { /** * @return float */ public function getCash(): float; }
-
-
CashBox.php
<?php namespace DesignPatterns\Structural\Adapter; use DesignPatterns\Structural\Adapter\Dollar\DollarInterface; /** * Class CashBox * @package DesignPatterns\Structural\Adapter */ class CashBox { /** * @var float */ protected $cash; /** * @return float */ public function getSumCashInCashBox() { return $this->cash; } /** * @param DollarInterface $dollarCash * * @return void */ public function setCash(DollarInterface $dollarCash) { $this->cash += $dollarCash->getCash(); } }
-
EuroAdapter.php
<?php namespace DesignPatterns\Structural\Adapter; use DesignPatterns\Structural\Adapter\Dollar\DollarInterface; use DesignPatterns\Structural\Adapter\Euro\EuroInterface; /** * Class EuroAdapter * @package DesignPatterns\Structural\Adapter */ class EuroAdapter implements DollarInterface { const EXCHANGE_RATE = 0.9; /** * @var EuroInterface */ protected $euroCash; /** * EuroAdapter constructor. * * @param EuroInterface $euroCash */ public function __construct(EuroInterface $euroCash) { $this->euroCash = $euroCash; } /** * @return float */ public function getCash(): float { return $this->euroCash->getCash() * self::EXCHANGE_RATE; } }
Test case:
AdapterTest.php
<?php
namespace DesignPatterns\Tests\Structural\Adapter;
use DesignPatterns\Structural\Adapter\CashBox;
use DesignPatterns\Structural\Adapter\Dollar\DollarsCash;
use DesignPatterns\Structural\Adapter\Euro\EuroCash;
use DesignPatterns\Structural\Adapter\EuroAdapter;
use TypeError;
class AdapterTest extends \PHPUnit_Framework_TestCase
{
public function testGetSumWithDollarCash()
{
$cashBox = new CashBox();
$dollarCash = new DollarsCash(15);
$cashBox->setCash($dollarCash);
$this->assertEquals($cashBox->getSumCashInCashBox(), $dollarCash->getCash());
}
public function testTypeErrorGetSumWithEuroCash()
{
$this->expectException(TypeError::class);
$cashBox = new CashBox();
$euroCash = new EuroCash(15);
$cashBox->setCash($euroCash);
}
public function testAdapterForEuroCash()
{
$cashBox = new CashBox();
$euroCash = new EuroCash(10);
$dollarCash = new DollarsCash(15);
$euroCashAdapter = new EuroAdapter($euroCash);
$cashBox->setCash($euroCashAdapter);
$cashBox->setCash($dollarCash);
$this->assertEquals($cashBox->getSumCashInCashBox(), $euroCashAdapter->getCash() + $dollarCash->getCash());
}
}