当前位置: 首页 > news >正文

PHP设计模式策略与适配器实战

PHP设计模式策略与适配器实战

策略模式和适配器模式在实际项目中非常常用。策略模式让你能动态切换算法,适配器模式让不兼容的接口能协同工作。今天就用实战例子说明这两种模式。

策略模式把算法封装成独立的类,客户端可以根据需要选择不同的算法。最常见的例子是支付方式的选择。

```php
interface PaymentGateway
{
public function pay(float $amount, array $params = []): array;
public function refund(string $transactionId): array;
public function getName(): string;
}

class AlipayGateway implements PaymentGateway
{
private string $appId;
private string $privateKey;

public function __construct(string $appId, string $privateKey)
{
$this->appId = $appId;
$this->privateKey = $privateKey;
}

public function pay(float $amount, array $params = []): array
{
return [
'channel' => 'alipay',
'trade_no' => 'ALI' . date('Ymd') . uniqid(),
'amount' => $amount,
'status' => 'success',
'timestamp' => date('Y-m-d H:i:s'),
];
}

public function refund(string $transactionId): array
{
return [
'channel' => 'alipay',
'refund_no' => 'REF' . $transactionId,
'status' => 'success',
];
}

public function getName(): string { return '支付宝'; }
}

class WechatGateway implements PaymentGateway
{
private string $appId;
private string $mchId;

public function __construct(string $appId, string $mchId)
{
$this->appId = $appId;
$this->mchId = $mchId;
}

public function pay(float $amount, array $params = []): array
{
return [
'channel' => 'wechat',
'trade_no' => 'WX' . date('Ymd') . uniqid(),
'amount' => $amount,
'status' => 'success',
'openid' => $params['openid'] ?? '',
];
}

public function refund(string $transactionId): array
{
return [
'channel' => 'wechat',
'refund_no' => 'REF' . $transactionId,
'status' => 'success',
];
}

public function getName(): string { return '微信支付'; }
}

class PaymentContext
{
private ?PaymentGateway $gateway = null;

public function __construct(PaymentGateway $gateway)
{
$this->gateway = $gateway;
}

public function setGateway(PaymentGateway $gateway): void
{
$this->gateway = $gateway;
}

public function executePayment(float $amount, array $params = []): array
{
if ($this->gateway === null) {
throw new RuntimeException('未设置支付网关');
}

$result = $this->gateway->pay($amount, $params);
$this->logPayment($result);
return $result;
}

private function logPayment(array $result): void
{
$log = sprintf(
"[%s] 支付: %s 交易号: %s 金额: %.2f 状态: %s\n",
date('Y-m-d H:i:s'),
$result['channel'],
$result['trade_no'],
$result['amount'],
$result['status']
);
file_put_contents('/tmp/payments.log', $log, FILE_APPEND);
}
}

$alipay = new AlipayGateway('app123', 'key456');
$payment = new PaymentContext($alipay);
$result = $payment->executePayment(99.99);
print_r($result);

// 切换到微信
$payment->setGateway(new WechatGateway('wx_app', 'mch001'));
$result2 = $payment->executePayment(199.99, ['openid' => 'o12345']);
print_r($result2);
?>
```

数据导出也是策略模式的常见应用。不同的导出格式对应不同的策略。

```php
interface ExportStrategy
{
public function export(array $data): string;
public function getContentType(): string;
public function getExtension(): string;
}

class JsonExport implements ExportStrategy
{
public function export(array $data): string
{
return json_encode($data, JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT);
}

public function getContentType(): string { return 'application/json'; }
public function getExtension(): string { return 'json'; }
}

class CsvExport implements ExportStrategy
{
public function export(array $data): string
{
if (empty($data)) return '';

$output = fopen('php://temp', 'r+');
fputcsv($output, array_keys($data[0]));

foreach ($data as $row) {
fputcsv($output, $row);
}

rewind($output);
$content = stream_get_contents($output);
fclose($output);

return $content;
}

public function getContentType(): string { return 'text/csv'; }
public function getExtension(): string { return 'csv'; }
}

class XmlExport implements ExportStrategy
{
public function export(array $data): string
{
$doc = new DOMDocument('1.0', 'UTF-8');
$doc->formatOutput = true;
$root = $doc->createElement('data');

foreach ($data as $item) {
$element = $doc->createElement('item');
foreach ($item as $key => $value) {
$child = $doc->createElement($key);
$child->appendChild($doc->createTextNode((string)$value));
$element->appendChild($child);
}
$root->appendChild($element);
}

$doc->appendChild($root);
return $doc->saveXML();
}

public function getContentType(): string { return 'application/xml'; }
public function getExtension(): string { return 'xml'; }
}

class DataExporter
{
private ExportStrategy $strategy;

public function __construct(ExportStrategy $strategy)
{
$this->strategy = $strategy;
}

public function export(array $data, string $filename): void
{
$content = $this->strategy->export($data);
$fullFilename = $filename . '.' . $this->strategy->getExtension();

header('Content-Type: ' . $this->strategy->getContentType());
header('Content-Disposition: attachment; filename="' . $fullFilename . '"');
header('Content-Length: ' . strlen($content));
echo $content;
}

public function exportToFile(array $data, string $path): string
{
$content = $this->strategy->export($data);
$fullPath = $path . '.' . $this->strategy->getExtension();
file_put_contents($fullPath, $content);
return $fullPath;
}
}

$data = [
['name' => '张三', 'age' => 28, 'email' => 'zhangsan@test.com'],
['name' => '李四', 'age' => 35, 'email' => 'lisi@test.com'],
];

$exporter = new DataExporter(new JsonExport());
$path = $exporter->exportToFile($data, '/tmp/export');
echo "导出到: $path\n";

$exporter2 = new DataExporter(new CsvExport());
$path2 = $exporter2->exportToFile($data, '/tmp/export');
echo "导出到: $path2\n";
?>
```

适配器模式用来让不兼容的接口协同工作。在整合第三方库时特别有用。

```php
// 目标接口
interface LogInterface
{
public function info(string $message): void;
public function error(string $message): void;
public function warning(string $message): void;
}

// 旧系统实现的日志
class SimpleFileLogger
{
private string $path;

public function __construct(string $path)
{
$this->path = $path;
}

public function write(string $level, string $message): void
{
$line = sprintf(
"[%s] %s: %s\n",
date('Y-m-d H:i:s'),
$level,
$message
);
file_put_contents($this->path, $line, FILE_APPEND);
}
}

// 适配器
class SimpleLoggerAdapter implements LogInterface
{
private SimpleFileLogger $logger;

public function __construct(SimpleFileLogger $logger)
{
$this->logger = $logger;
}

public function info(string $message): void
{
$this->logger->write('INFO', $message);
}

public function error(string $message): void
{
$this->logger->write('ERROR', $message);
}

public function warning(string $message): void
{
$this->logger->write('WARNING', $message);
}
}

$logger = new SimpleLoggerAdapter(new SimpleFileLogger('/tmp/app.log'));
$logger->info('用户登录成功');
$logger->error('数据库连接失败');
echo "日志已写入\n";
?>
```

策略模式和适配器模式的核心思想都是面向接口编程。策略模式是"有不同的实现,根据情况选用",适配器模式是"接口不兼容,包一层转接"。理解了这两种模式,代码的扩展性和灵活性会提升很多。

http://www.cnnetsun.cn/news/2745591.html

相关文章:

  • 【github】多人协作使用git,从本地更新仓库-笔记
  • 森林火灾检测图像数据集 nc=1 标签names: [‘Fire’] 名称:【‘火’】共7793张,近似9:1比例划分,标注txt格式。可直接用于模型训练。
  • SAP-ABAP:SAP基础数据校验工具开发系列博客(共5篇)第四篇:可视化校验结果输出与问题闭环流程实现
  • Swin Transformer V2模型部署终极指南:NPU与CPU双环境快速配置教程
  • MATLAB调用STK11的Astrogator模块,手把手教你自动化设置卫星轨道机动(附完整代码)
  • ByteDance-Seed/TaskMem未来展望:Qwen3VLMoe模型的技术路线图与社区贡献指南
  • Dramabox API开发指南:如何集成情感语音合成到你的应用程序
  • PHP设计模式观察者与中介者实现
  • 如何利用Google 10000英语词频库提升NLP应用性能?
  • 别再纠结TB6600了!用拇指大的A4988驱动42步进电机,实测DIY升降台(附51/STM32/FPGA代码)
  • MySQL 8.0在Docker中大小写敏感配置终极指南:从原理到实战
  • 收藏!前端程序员必看:AI来了,我们真的会失业吗?附自救指南
  • 3个核心技巧:让Windows任务栏从实用工具变身视觉艺术
  • GPT-5.5级大模型:语义理解与意图推演的技术跃迁
  • 系统架构设计师下午题选题策略:五选三怎么选最容易
  • 008、STM32单片机分享:智能风扇系统
  • CANNBot SIMT API总览
  • 停止用AI写代码,开始用大脑建系统:从“提示词搬运工”到“架构决策者”的7天跃迁训练
  • 快手面试官问:Agent跑50轮突然变傻了
  • 崩坏星穹铁道自动化工具:三月七小助手完全指南
  • GTE-large-zh vs BGE-large-zh:全面对比与迁移学习方案终极指南
  • 天线阵列S2P批量解析与方向图参数一键计算(含高低频适配)
  • 别再只用-transparentcolor了!用Tkinter窗口叠加,轻松实现聊天框、悬浮球等UI的半透明效果
  • GPT-4 Turbo实战指南:128K上下文与跨模态理解如何重构AI落地
  • 如何快速掌握OpenCore Legacy Patcher:让旧Mac重获新生的完整指南
  • 告别SLAM跟踪丢失就卡住!用ORB-SLAM Atlas实现‘无缝续命’的保姆级原理拆解
  • AMCL定位突然失效?可能是你没处理好‘机器人绑架’和‘里程计漂移’
  • STM32F103C8T6驱动MAX30205测温:手把手教你搞定I2C多从机地址配置与数据读取
  • 终极指南:深入理解MOSS-Audio-Tokenizer-Nano-ONNX架构:编码器与流式解码器工作原理
  • 内部专家的“经验萃取”远比“人才引进”更重要