模式定義與角色
適配器模式 將一個類的接口轉換為客戶期望的另一接口,使原本不兼容的類能協同工作。
| 角色 | 說明 | 本文對應 |
| Target (目標接口) | 客戶端期望的接口 | SoccerPlayer |
| Adaptee (被適配者) | 現有不兼容接口 | Messi (中文方法名) |
| Adapter (適配器) | 轉換接口的核心類 | Adapter 實現 SoccerPlayer |
| Client (客戶端) | 使用目標接口 | 測試代碼 |
適用場景
- 復用現有類但接口不匹配
- 創建可復用類與未知類協作
- 適配第三方庫/遺留代碼/外部 API
案例一:標準結構實現
<?php
// 目標接口
interface Target {
public function simpleMethod1();
public function simpleMethod2();
}
// 被適配者:只有 method1
class Adaptee {
public function simpleMethod1() {
echo "Adaptee simpleMethod1\n";
}
}
// 適配器:組合模式持有 Adaptee
class Adapter implements Target {
private $adaptee;
public function __construct(Adaptee $adaptee) {
$this->adaptee = $adaptee;
}
public function simpleMethod1() {
return $this->adaptee->simpleMethod1(); // 委派
}
public function simpleMethod2() {
echo "Adapter simpleMethod2\n"; // 自行實現
}
}
// 客戶端
class Client {
public static function main() {
$adaptee = new Adaptee();
$adapter = new Adapter($adaptee);
$adapter->simpleMethod1();
$adapter->simpleMethod2();
}
}
Client::main();
// 輸出:
// Adaptee simpleMethod1
// Adapter simpleMethod2
案例二:足球換人系統(生動實戰)
領域模型
// 統一運動員接口
interface SoccerPlayer {
public function attack();
public function defense();
}
// 陣容球員
class Forward implements SoccerPlayer {
public function attack() { echo "前鋒攻擊\n"; }
public function defense() { echo "前鋒防守\n"; }
}
class Center implements SoccerPlayer {
public function attack() { echo "中鋒攻擊\n"; }
public function defense() { echo "中鋒防守\n"; }
}
// 明星球員:接口不兼容(中文方法名)
class Messi {
public function 進攻() { echo "梅西進攻\n"; }
public function 防守() { echo "梅西防守\n"; }
}
適配器讓梅西融入體系
class MessiAdapter implements SoccerPlayer {
private $messi;
public function __construct() {
$this->messi = new Messi();
}
public function attack() {
$this->messi->進攻(); // 方法名映射
}
public function defense() {
$this->messi->防守();
}
}
客戶端調用
$player1 = new Forward();
echo "前鋒上場:\n";
$player1->attack();
$player1->defense();
echo "\n---\n梅西上場:\n";
$messi = new MessiAdapter();
$messi->attack();
$messi->defense();
/*
前鋒上場:
前鋒攻擊
前鋒防守
---
梅西上場:
梅西進攻
梅西防守
*/
兩種適配器變體
| 類型 | 實現方式 | 優點 | 缺點 |
| 對象適配器 | 組合 + 委派(本文兩例) | 可適配子類、靈活、符合合成復用 | 需重寫委派方法 |
| 類適配器 | 多重繼承 (PHP 用 traits 模擬) | 可覆寫 Adaptee 行為 | PHP 不支援多重繼承、耦合度高 |
實戰擴展:雙向適配器
// 當需要雙向轉換時
interface LegacyLogger {
public function log(string $msg);
}
interface ModernLogger {
public function info(string $msg);
public function error(string $msg);
}
class BiDirectionalAdapter implements LegacyLogger, ModernLogger {
private $legacy;
private $modern;
public function __construct($legacy = null, $modern = null) {
$this->legacy = $legacy;
$this->modern = $modern;
}
// Legacy → Modern
public function log(string $msg) {
$this->modern?->info($msg);
}
// Modern → Legacy
public function info(string $msg) {
$this->legacy?->log("[INFO] $msg");
}
public function error(string $msg) {
$this->legacy?->log("[ERROR] $msg");
}
}
最佳實踐建議
- 優先組合: 對象適配器靈活解耦
2. 接口隔離: 適配器只實現目標接口需求子集
3. 命名規範: 類名以 Adapter 結尾,方法名保持目標接口語義
4. 異常轉換: 適配層統一異常類型,隱藏實現細節
5. 文檔說明: 註釋被適配者來源、版本、映射邏輯
總結
適配器模式是**系統集成、遺留重構、第三方庫接入**的利器。核心思想:**不修改現有代碼,通過中間層轉換接口**。PHP 中採用組合實現對象適配器,配合介面契約,實現高內聚低耦合的擴展架構。
copyright ©
萬盛學電腦網 all rights reserved