PHP设计模式策略与适配器实战
PHP设计模式策略与适配器实战策略模式和适配器模式在实际项目中非常常用。策略模式让你能动态切换算法适配器模式让不兼容的接口能协同工作。今天就用实战例子说明这两种模式。策略模式把算法封装成独立的类客户端可以根据需要选择不同的算法。最常见的例子是支付方式的选择。phpinterface 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);?数据导出也是策略模式的常见应用。不同的导出格式对应不同的策略。phpinterface 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 zhangsantest.com],[name 李四, age 35, email lisitest.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;?策略模式和适配器模式的核心思想都是面向接口编程。策略模式是有不同的实现根据情况选用适配器模式是接口不兼容包一层转接。理解了这两种模式代码的扩展性和灵活性会提升很多。