本文目录导读:

在PHP项目中,适配器模式(Adapter Pattern)用于解决接口不兼容的问题,让原本因接口不同而无法协作的类能够协同工作,针对“兼容多接口”的需求,最核心的思路是将多个不同的接口统一为一个目标接口,客户端只依赖这个目标接口,而适配器负责将多个不同的源接口转换为目标接口。
下面给出几种常见的实现方案,以及一个完整的实战示例。
核心思想
假设你的系统需要与多个第三方支付网关(支付宝、微信、PayPal)交互,每个网关都有自己的接口签名和调用方式,适配器模式允许你定义一个统一的 PaymentInterface,然后为每个网关创建一个适配器类,这些适配器将网关特有的 API 调用封装成统一的接口方法。
实现方式
方案A:类适配器(使用继承)
- 适用场景:适配器需要继承被适配的类,并实现目标接口。
- 优点:可以直接访问被适配类的 protected 方法。
- 缺点:PHP 单继承限制,一个适配器只能适配一个类。
// 目标接口
interface PaymentInterface {
public function pay(float $amount): string;
}
// 被适配的类(第三方支付SDK)
class AlipaySDK {
public function alipayRequest(float $amount): string {
return "Alipay paid: {$amount}";
}
}
// 类适配器
class AlipayAdapter extends AlipaySDK implements PaymentInterface {
public function pay(float $amount): string {
return $this->alipayRequest($amount);
}
}
方案B:对象适配器(使用组合)—— 推荐
- 适用场景:需要同时适配多个接口、或者不想破坏被适配类的封装。
- 优点:灵活,可适配任意数量的接口,符合组合优于继承原则。
// 目标接口
interface PaymentInterface {
public function pay(float $amount): string;
}
// 多个被适配的类
class WechatPay {
public function wechatRequest(float $amount): string {
return "Wechat paid: {$amount}";
}
}
class PayPal {
public function sendPayment(float $amount): string {
return "PayPal paid: {$amount}";
}
}
// 对象适配器(组合方式)
class WechatAdapter implements PaymentInterface {
private WechatPay $wechatPay;
public function __construct(WechatPay $wechatPay) {
$this->wechatPay = $wechatPay;
}
public function pay(float $amount): string {
return $this->wechatPay->wechatRequest($amount);
}
}
class PayPalAdapter implements PaymentInterface {
private PayPal $payPal;
public function __construct(PayPal $payPal) {
$this->payPal = $payPal;
}
public function pay(float $amount): string {
// 在适配器内部做参数转换、签名、异常处理等
return $this->payPal->sendPayment($amount);
}
}
方案C:适配多个接口的聚合适配器
当需要同时适配多个不同来源的接口(例如既要调用支付接口,又要调用日志接口)时,可以设计一个聚合适配器。
// 目标接口1
interface PaymentInterface {
public function pay(float $amount): string;
}
// 目标接口2
interface LoggerInterface {
public function log(string $message): void;
}
// 被适配的第三方类
class ThirdPartySDK {
public function doPayment(float $amount): string {
return "ThirdParty paid: {$amount}";
}
public function writeLog(string $msg): void {
echo "[Log]: {$msg}" . PHP_EOL;
}
}
// 聚合适配器,同时实现两个目标接口
class ThirdPartyAdapter implements PaymentInterface, LoggerInterface {
private ThirdPartySDK $sdk;
public function __construct(ThirdPartySDK $sdk) {
$this->sdk = $sdk;
}
public function pay(float $amount): string {
// 可以做一些预处理、参数映射
return $this->sdk->doPayment($amount);
}
public function log(string $message): void {
$this->sdk->writeLog($message);
}
}
实战示例:多接口支付系统
假设你要对接支付宝、微信、银联三个支付渠道,每个渠道的接口签名、参数、返回格式都不同。
定义统一接口
interface UnifiedPayment {
public function charge(float $amount, array $orderInfo): array;
public function refund(string $transactionId, float $amount): bool;
}
创建多个适配器
class AlipayAdapter implements UnifiedPayment {
private AlipayService $alipay;
public function __construct(AlipayService $alipay) {
$this->alipay = $alipay;
}
public function charge(float $amount, array $orderInfo): array {
// 将统一参数转换为支付宝SDK需要的参数
$alipayParams = [
'total_amount' => $amount,
'subject' => $orderInfo['subject'],
'out_trade_no' => $orderInfo['orderNo'],
];
$result = $this->alipay->tradePagePay($alipayParams);
return ['success' => true, 'redirect_url' => $result];
}
public function refund(string $transactionId, float $amount): bool {
return $this->alipay->refund($transactionId, $amount);
}
}
class WechatAdapter implements UnifiedPayment {
// 类似上述逻辑,调用微信SDK
// ...
}
客户端使用
function processPayment(UnifiedPayment $payment, float $amount, array $order) {
$result = $payment->charge($amount, $order);
// 统一处理结果
return $result;
}
// 根据配置选择适配器
$config = ['channel' => 'alipay'];
$payment = match ($config['channel']) {
'alipay' => new AlipayAdapter(new AlipayService()),
'wechat' => new WechatAdapter(new WechatPayService()),
'unionpay' => new UnionPayAdapter(new UnionPayService()),
};
processPayment($payment, 100.00, ['subject' => 'Test', 'orderNo' => '20241001']);
如何兼容多个不同风格的接口?
当被适配的类有不同的方法签名、参数顺序、返回值类型时,适配器内部可以做以下几件事:
| 被适配接口风格 | 适配器内部处理 |
|---|---|
| 参数结构不同 | 做参数映射、重组、类型转换 |
| 方法命名不同 | 调用对应的方法并传递参数 |
| 返回值格式不同 | 解析返回值,统一为标准格式 |
| 异常处理不同 | 捕获第三方异常,抛出自定义业务异常 |
| 需要额外认证/签名 | 在适配器内部完成认证、签名逻辑 |
优缺点总结
优点
- 解耦:客户端代码与具体实现分离。
- 复用:复用已有的第三方库,无需修改其代码。
- 可扩展:新增一个渠道只需增加一个适配器类,符合开闭原则。
- 统一接口:多接口被统一,业务逻辑无需关心底层差异。
缺点
- 适配器数量随接入系统增多而增加。
- 过度使用可能导致系统结构复杂(可结合工厂模式创建适配器)。
最佳实践建议
- 优先使用对象适配器(组合):避免单继承限制,且不破坏被适配类的封装。
- 适配器不应包含业务逻辑:它只做接口转换和数据映射,业务判断放在调用方或服务层。
- 结合工厂模式创建适配器:根据配置动态生成合适的适配器实例。
- 使用接口定义契约:所有适配器实现同一个接口,客户端只依赖该接口。
- 做好单元测试:每个适配器应独立测试,验证参数映射和异常处理是否正确。
通过适配器模式,你的 PHP 项目可以优雅地对接任意数量、任意风格的第三方接口,同时保持核心业务代码的整洁和可维护性。
版权声明:NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播