1. 模式定义
首先我们来看看什么是适配器。 适配器的存在,就是为了将已存在的东西(接口)转换成适合我们需要、能被我们所利用的东西。在现实生活中,适配器更多的是作为一个中间层来实现这种转换作用。比如电源适配器,它是用于电流变换(整流)的设备。 适配器模式将一个类的接口转换成客户希望的另外一个接口,使得原本由于接口不兼容而不能一起工作的那些类可以在一起工作。
2. UML类图
image.png3. 示例代码
如下是一个假设的地铁闸机的一个场景。
最开始,地铁闸机只支持地铁卡过闸机,所以,闸机后台只支持SubwayCardInterface
这个接口。如下:
<?php
namespace DesignPattern\Structural\Adapter;
/**
* 交通卡接口
* Interface SubwayCardInterface
* @package Structural\Adapter
*/
interface SubwayCardInterface
{
//读取卡信息
public function readCard();
//记录进站
public function enterStation();
//出站进行扣费
public function outStationAndCost();
}
SubwayCard
实现接口SubwayCardInterface
,因此可以正确通过闸机。
<?php
namespace DesignPattern\Structural\Adapter;
/**
* 交通卡
* Class SubwayCard
* @package Structural\Adapter
*/
class SubwayCard implements SubwayCardInterface
{
public function readCard()
{
//作为交通卡,通过NFC 或者其他技术,读取卡信息
}
public function enterStation()
{
//记录进站
}
public function outStationAndCost()
{
//记录出站对卡信息进行扣费操作
}
}
但随着科技的发展,现在有各种过闸机的方式,我们以大都会的二维码为例。
二维码的接口QRCodeInterface
如下:
<?php
namespace DesignPattern\Structural\Adapter;
interface QRCodeInterface
{
//识别二维码
public function qrCodeRecognition();
//调用第三方的信息并记录进出站
public function enterOutStation();
//调用第三方的消费接口:将费用信息给到第三方,然后得到扣费结果
public function cost();
}
QRCode
类实现了QRCodeInterface
接口
<?php
namespace DesignPattern\Structural\Adapter;
class QRCode implements QRCodeInterface
{
//识别二维码
public function qrCodeRecognition(){
}
//调用第三方的信息并记录进出站
public function enterOutStation(){
}
//调用第三方的消费接口:将费用信息给到第三方,然后得到扣费结果
public function cost(){
}
}
那现在问题来了,闸机后台只支持SubwayCardInterface
接口,我们如何让他支持实现QRCodeInterface
接口的二维码类呢???
这个时候就需要我们的适配器SubwayCardAdapter
了,该适配器实现了SubwayCardInterface
接口,所以能够被闸机后台所使用。 适配器的构造方法参数为实现QRCodeInterface
接口的类,适配器将这些类的方法根据闸机后台支持的SubwayCardInterface
接口所声明的方法进行了转换实现。
<?php
namespace DesignPattern\Structural\Adapter;
/**
* 适配器:将二维码刷地铁接口通过本适配器转化为闸机所用的地铁卡刷地铁的方式
* Class SubwayCardAdapter
* @package Structural\Adapter
*/
class SubwayCardAdapter implements SubwayCardInterface
{
/** @var QRCodeInterface */
protected $qrCode;
public function __construct(QRCodeInterface $qrCode)
{
$this->qrCode = $qrCode;
}
public function readCard()
{
$this->qrCode->QRCodeRecognition();
}
public function enterStation()
{
$this->qrCode->enterOutStation();
}
public function outStationAndCost()
{
$this->qrCode->enterOutStation();
$this->qrCode->cost();
}
}
这样适配器就是作为一个中间层来实现了转换作用。
单元测试如下:
<?php
namespace DesignPattern\Tests;
use PHPUnit\Framework\TestCase;
use DesignPattern\Structural\Adapter\QRCode;
use DesignPattern\Structural\Adapter\SubwayCard;
use DesignPattern\Structural\Adapter\SubwayCardAdapter;
use DesignPattern\Structural\Adapter\SubwayCardInterface;
/**
* 测试单例模式
* Class SingletonTest
* @package Creational\Singleton\Tests
*/
class AdapterTest extends TestCase
{
/**
* @return array
*/
public function getSubwayCard()
{
return array(
array(new SubwayCard()),
// 我们在适配器中引入了电子书
array(new SubwayCardAdapter(new QRCode()))
);
}
/**
* 地铁闸机后台地铁卡,不知道还有二维码
* 实际上第一个是地铁卡, 第二个是二维码
* 但是对地铁闸机后台来说代码一致,不需要做任何改动
*
* @param SubwayCardInterface $subwayCard
*
* @dataProvider getSubwayCard
*/
public function testSubwayTurnstile(SubwayCardInterface $subwayCard)
{
$this->assertTrue(method_exists($subwayCard, 'readCard'));
$this->assertTrue(method_exists($subwayCard, 'enterStation'));
$this->assertTrue(method_exists($subwayCard, 'outStationAndCost'));
}
}
本教程中的实现仅为我个人的设想,实际实现本人并不了解
参考文档:https://laravelacademy.org/post/2660
教程源码:https://github.com/SylviaYuan1995/DesignPatternDemo
网友评论