模式概念
适配器也称为包装器,顾名思义就是:能够使两个不同的事情之间进行相互兼容
应用场景
·兼容两个不同的应用场景时使用
UML类图
代码实现
BookInterface.php
<?php
namespace DesignPatterns\Structural\Adapter;
interface BookInterface
{
public function turnPage();
public function open();
public function getPage(): int;
}
Book.php
<?php
namespace DesignPatterns\Structural\Adapter;
class Book implements BookInterface
{
/**
* @var int
*/
private $page;
public function open()
{
$this->page = 1;
}
public function turnPage()
{
$this->page++;
}
public function getPage(): int
{
return $this->page;
}
}
EbookInterface.php
<?php
namespace DesignPatterns\Structural\Adapter;
interface EBookInterface
{
public function unlock();
public function pressNext();
/**
* returns current page and total number of pages, like [10, 100] is page 10 of 100
*
* @return int[]
*/
public function getPage(): array;
}
Kindle.php
<?php
namespace DesignPatterns\Structural\Adapter;
/**
* this is the adapted class. In production code, this could be a class from another package, some vendor code.
* Notice that it uses another naming scheme and the implementation does something similar but in another way
*/
class Kindle implements EBookInterface
{
/**
* @var int
*/
private $page = 1;
/**
* @var int
*/
private $totalPages = 100;
public function pressNext()
{
$this->page++;
}
public function unlock()
{
}
/**
* returns current page and total number of pages, like [10, 100] is page 10 of 100
*
* @return int[]
*/
public function getPage(): array
{
return [$this->page, $this->totalPages];
}
}
EBookAdapter.php(最为关键的适配器类)
<?php
namespace DesignPatterns\Structural\Adapter;
/**
* This is the adapter here. Notice it implements BookInterface,
* therefore you don't have to change the code of the client which is using a Book
*/
class EBookAdapter implements BookInterface
{
/**
* @var EBookInterface
*/
protected $eBook;
/**
* @param EBookInterface $eBook
*/
public function __construct(EBookInterface $eBook)
{
$this->eBook = $eBook;
}
/**
* This class makes the proper translation from one interface to another.
*/
public function open()
{
$this->eBook->unlock();
}
public function turnPage()
{
$this->eBook->pressNext();
}
/**
* notice the adapted behavior here: EBookInterface::getPage() will return two integers, but BookInterface
* supports only a current page getter, so we adapt the behavior here
*
* @return int
*/
public function getPage(): int
{
return $this->eBook->getPage()[0];
}
}
AdapterTest.php
<?php
namespace DesignPatterns\Structural\Adapter\Tests;
use DesignPatterns\Structural\Adapter\Book;
use DesignPatterns\Structural\Adapter\EBookAdapter;
use DesignPatterns\Structural\Adapter\Kindle;
use PHPUnit\Framework\TestCase;
class AdapterTest extends TestCase
{
public function testCanTurnPageOnBook()
{
$book = new Book();
$book->open();
$book->turnPage();
$this->assertEquals(2, $book->getPage());
}
public function testCanTurnPageOnKindleLikeInANormalBook()
{
$kindle = new Kindle();
$book = new EBookAdapter($kindle);
$book->open();
$book->turnPage();
$this->assertEquals(2, $book->getPage());
}
}
心得总结
总体而言:适配器就是在原来两个相对功能比较独立的情况(比如:一个移动端适配、一个PC端适配)然后客户端(外部请求)使用时尽量减少变动,增加适配器类进行代码的兼容;