本文目录导读:

适配器模式(Adapter Pattern)在PHP中非常实用,主要用于解决接口不兼容的问题,我来通过几个实际场景详细讲解。
基础概念
适配器模式允许不兼容的接口协同工作,就像电源转换插头一样,让不同的接口能够对接。
经典实现方式
类适配器(继承方式)
<?php
// 目标接口(客户端期望的接口)
interface PaymentGateway {
public function pay($amount);
public function refund($transactionId);
}
// 第三方支付类(不兼容的类)
class ThirdPartyPay
{
public function sendMoney($amount) {
return "通过第三方支付: {$amount}元";
}
public function returnMoney($id) {
return "退款编号: {$id}";
}
}
// 适配器类
class PaymentAdapter extends ThirdPartyPay implements PaymentGateway
{
public function pay($amount) {
// 转换接口
return $this->sendMoney($amount);
}
public function refund($transactionId) {
// 转换接口
return $this->returnMoney($transactionId);
}
}
// 客户端使用
class OrderService {
private $paymentGateway;
public function __construct(PaymentGateway $gateway) {
$this->paymentGateway = $gateway;
}
public function checkout($amount) {
return $this->paymentGateway->pay($amount);
}
}
// 使用示例
$adapter = new PaymentAdapter();
$order = new OrderService($adapter);
echo $order->checkout(100);
对象适配器(组合方式)- 推荐
<?php
// 接口定义
interface Notification {
public function send($to, $message);
}
// 微信通知(不兼容的接口)
class WeChatNotifier
{
public function sendWeChat($openId, $content) {
return "微信发送给 {$openId}: {$content}";
}
}
// 邮件通知(不兼容的接口)
class EmailNotifier
{
public function sendEmail($address, $subject, $body) {
return "邮件发送给 {$address}: {$subject} - {$body}";
}
}
// 统一的适配器
class NotificationAdapter implements Notification {
private $target;
public function __construct($target) {
$this->target = $target;
}
public function send($to, $message) {
if ($this->target instanceof WeChatNotifier) {
return $this->target->sendWeChat($to, $message);
}
if ($this->target instanceof EmailNotifier) {
return $this->target->sendEmail($to, '系统通知', $message);
}
throw new Exception("不支持的适配器类型");
}
}
// 客户端使用
class UserService {
private $notifier;
public function __construct(Notification $notifier) {
$this->notifier = $notifier;
}
public function sendNotification($user) {
return $this->notifier->send($user->getContact(), "欢迎加入");
}
}
// 使用示例
$userService = new UserService(
new NotificationAdapter(new WeChatNotifier())
);
实际应用场景
场景1:数据库操作统一接口
<?php
// 统一的缓存接口
interface CacheInterface {
public function get($key);
public function set($key, $value, $expire = 300);
public function delete($key);
}
// Redis实现
class RedisCache {
private $redis;
public function __construct() {
$this->redis = new Redis();
$this->redis->connect('127.0.0.1', 6379);
}
public function getData($key) {
return $this->redis->get($key);
}
public function setData($key, $data, $ttl) {
return $this->redis->setex($key, $ttl, $data);
}
public function remove($key) {
return $this->redis->del($key);
}
}
// Memcached实现
class MemcachedCache implements CacheInterface {
private $memcached;
public function __construct() {
$this->memcached = new Memcached();
$this->memcached->addServer('localhost', 11211);
}
public function get($key) {
return $this->memcached->get($key);
}
public function set($key, $value, $expire = 300) {
return $this->memcached->set($key, $value, $expire);
}
public function delete($key) {
return $this->memcached->delete($key);
}
}
// Redis适配器
class RedisCacheAdapter implements CacheInterface {
private $redisCache;
public function __construct(RedisCache $redisCache) {
$this->redisCache = $redisCache;
}
public function get($key) {
return $this->redisCache->getData($key);
}
public function set($key, $value, $expire = 300) {
return $this->redisCache->setData($key, $value, $expire);
}
public function delete($key) {
return $this->redisCache->remove($key);
}
}
// 业务逻辑使用
class ProductService {
private $cache;
public function __construct(CacheInterface $cache) {
$this->cache = $cache;
}
public function getProduct($id) {
// 先查缓存
$cached = $this->cache->get("product:{$id}");
if ($cached) {
return unserialize($cached);
}
// 数据库查询逻辑...
$product = ['id' => $id, 'name' => '商品名称'];
// 写入缓存
$this->cache->set("product:{$id}", serialize($product));
return $product;
}
}
// 切换缓存系统只需改变适配器
$cache = new RedisCacheAdapter(new RedisCache());
$productService = new ProductService($cache);
场景2:第三方API集成
<?php
// 短信发送接口
interface SmsSender {
public function send($phone, $message);
}
// 阿里云短信
class AliYunSms {
public function sendSms($params) {
// Api具体调用逻辑
return "阿里云发送: {$params['phone']} - {$params['message']}";
}
}
// 腾讯云短信
class TencentSms {
public function sendMessage($mobile, $content, $sign) {
return "腾讯云发送: {$mobile} - {$content} (签名: {$sign})";
}
}
// 阿里云适配器
class AliYunAdapter implements SmsSender {
private $aliYun;
public function __construct(AliYunSms $aliYun) {
$this->aliYun = $aliYun;
}
public function send($phone, $message) {
return $this->aliYun->sendSms([
'phone' => $phone,
'message' => $message,
]);
}
}
// 腾讯云适配器
class TencentAdapter implements SmsSender {
private $tencent;
public function __construct(TencentSms $tencent) {
$this->tencent = $tencent;
}
public function send($phone, $message) {
return $this->tencent->sendMessage($phone, $message, '【公司名称】');
}
}
// 配置类
class SmsConfig {
public static function getSmsSender() {
$provider = env('SMS_PROVIDER', 'aliyun');
if ($provider === 'aliyun') {
return new AliYunAdapter(new AliYunSms());
}
if ($provider === 'tencent') {
return new TencentAdapter(new TencentSms());
}
throw new Exception("不支持的短信服务商");
}
}
// 使用
class UserController {
public function sendVerifyCode($phone) {
$sender = SmsConfig::getSmsSender();
$code = rand(100000, 999999);
return $sender->send($phone, "验证码: {$code}");
}
}
Laravel中的适配器模式
<?php
namespace App\Adapters;
// 在Laravel中,适配器常用于Service Provider
use Illuminate\Support\ServiceProvider;
class PaymentServiceProvider extends ServiceProvider
{
public function register()
{
$this->app->singleton(PaymentGateway::class, function ($app) {
$driver = config('payment.driver');
switch ($driver) {
case 'stripe':
return new StripeAdapter(new StripeClient());
case 'alipay':
return new AlipayAdapter(new AlipayClient());
default:
throw new \Exception("不支持的支付方式");
}
});
}
}
最佳实践建议
适配器结构
<?php
// 定义统一的适配器接口
interface CacheAdapter {
public function get($key);
public function set($key, $value, $ttl = null);
public function delete($key);
public function clear();
}
// 抽象基础适配器
abstract class BaseCacheAdapter implements CacheAdapter {
protected $client;
protected function validateKey($key) {
if (empty($key)) {
throw new \InvalidArgumentException("Key cannot be empty");
}
}
protected function serializeData($data) {
return serialize($data);
}
protected function unserializeData($data) {
return unserialize($data);
}
}
注意事项
- 接口隔离:适配不同接口,但保持简单
- 错误处理:适配器要处理好异常
- 测试友好:方便Mock和测试
- 性能考虑:避免过度复杂转换
实战要点
<?php
// 统一异常处理
class AdapterException extends \Exception {}
interface ExportAdapter {
public function export($data, $type);
}
class JsonAdapter implements ExportAdapter {
public function export($data, $type) {
if ($type !== 'json') {
throw new AdapterException("Format not supported");
}
return json_encode($data);
}
}
class XmlAdapter implements ExportAdapter {
public function export($data, $type) {
if ($type !== 'xml') {
throw new AdapterException("Format not supported");
}
// XML转换逻辑
return $this->arrayToXml($data);
}
}
// 工厂模式结合适配器
class ExportFactory {
public static function create($format) {
$adapters = [
'json' => new JsonAdapter(),
'xml' => new XmlAdapter(),
];
if (!isset($adapters[$format])) {
throw new AdapterException("Unsupported format: {$format}");
}
return $adapters[$format];
}
}
性能优化技巧
<?php
// 适配器缓存
class AdapterCache {
private static $instances = [];
public static function get($adapterClass) {
if (!isset(self::$instances[$adapterClass])) {
self::$instances[$adapterClass] = new $adapterClass();
}
return self::$instances[$adapterClass];
}
}
// 延迟加载
class LazyLoadAdapter implements Notification {
private $target;
private $targetClass;
public function __construct($targetClass, $options = []) {
$this->targetClass = $targetClass;
$this->options = $options;
}
private function getTarget() {
if (!$this->target) {
$this->target = new $this->targetClass($this->options);
}
return $this->target;
}
public function send($to, $message) {
return $this->getTarget()->send($to, $message);
}
}
适配器模式在PHP中:
- 核心价值:让不兼容代码协同工作
- 使用场景:第三方集成、遗留系统整合、统一接口
- 实现要点:接口清晰、转换简单、错误处理完善
- 实际应用:支付、短信、缓存、文件存储等系统集成
适配器是为了适配,不是重构,如果两套接口本质相同,只是表达方式不同,才适合用适配器。