当前位置: 首页 > 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.zskr.cn/news/1459788.html

相关文章:

  • 从一道CTF题看PHP Session反序列化:手把手教你复现HarekazeCTF2019的Easy Notes
  • 气井井口压力已知时快速推算井底流压的MATLAB工具集
  • GLM-5.1办公语义理解器:让AI真正读懂任务意图与组织规则
  • VC6环境下用MFC开发的纯文本通讯录工具,带完整增删查改功能和源码
  • DLSS状态指示器终极指南:如何轻松监控游戏AI超分辨率性能
  • 零基础自学网安总找不到靠谱资料?完整自学步骤全梳理,配套对应系统视频教程 + 详细学习笔记,告别碎片化学习,新手少走半年弯路
  • WBench-weights核心模型详解:CLIP、DINOv2、Qwen2-VL等15个模型的完整对比
  • 即梦去水印保存怎么还有水印?实测这3种方法100%有效(附免费工具) - 科技热点发布
  • WebPlotDigitizer:3步将科研图表数据智能提取为Excel表格
  • Steam成就管理终极指南:如何使用SAM快速解锁你的游戏成就
  • 别再到处找教程了!JDK 1.8/11/17下keytool操作证书的保姆级命令手册(含Windows/Linux路径差异)
  • 基于2008–2028年文旅数据的Python实操包:用随机森林跑通旅游收入预测与影响因子分析
  • SpringBoot项目里,如何用PostgreSQL持久化Quartz定时任务(附完整代码和表结构)
  • 班级亲子照片投票活动,用小程序评选超省心 - 微信投票小程序
  • 74HC165级联踩坑实录:STM32读取32路开关状态,时序调试与常见问题排查
  • Swin Transformer V2模型部署终极指南:NPU与CPU双环境快速配置教程
  • 用主线内核+Uboot,让吃灰的全志A13山寨平板变身Linux开发板(附完整DTS配置)
  • 别再乱改my.cnf了!Docker+MySQL 8.0大小写敏感配置的一劳永逸方法
  • 新手教程:github访问受阻时,用快马ai生成你的第一个网页
  • YOLO11涨点优化:训练技巧 | 使用标签平滑(Label Smoothing)配合余弦退火学习率,防止过拟合,稳步提点
  • 明星合作预算与方案怎么做?一份从询价到签约落地的全流程决策指南 - GrowthUME
  • 终极免费解锁WeMod专业版:2026年完整指南与避坑手册
  • 2026年成都、武汉、深圳坤沙酱酒定制与加盟怎么选?盈贵人村超同款酱酒深度横评 - 精选优质企业推荐官
  • 如何利用Google 10000英语词频库提升NLP应用性能?
  • ensp配置效率提升秘籍:快马AI自动生成标准化网络模板
  • 如何快速上手Flan-T5-TSA-THoR:5分钟完成目标情感分析
  • 2026无锡装意式极简全屋定制,我连跑了三个小区看邻居家落地 - 高定
  • llm-jp-3-1.8b-instruct実践教程:Pythonで日本語テキスト生成を実現する方法
  • 如何快速美化foobar2000:5个简单步骤提升音乐播放体验
  • # 2026年广州同城婚介脱单公司实力排行榜:5大权威推荐 - 十大品牌榜