首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> 網頁程式設計 >> PHP 程式設計 >> PHP 綜合知識

PHP 設計模式:適配器模式整合第三方庫版本差異

     編輯:PHP 綜合知識

適配器模式:統一介面吸收外部 API 變更

第三方庫升級導致介面變更 (方法重命名、參數調整、回傳值改變) 時,適配器模式讓你在不修改核心業務代碼的情況下平滑遷移。

情境:HelloWorld 庫從 v1 升級 v2

<?php
// ===== 版本 1 (舊版,既有代碼依賴此介面) =====
class HwLibV1 {
    public function hello(): string { return 'Hello '; }
    public function world(): string { return 'World!'; }
}

// 既有代碼使用方式
$lib = new HwLibV1();
echo $lib->hello() . $lib->world(); // "Hello World!"

// ===== 版本 2 (新版,介面已變更) =====
class HwLibV2 {
    public function greet(): string { return 'Greetings and Salutations '; }
    public function world(): string { return 'World!'; }
}
// hello() 已移除,改為 greet()
?>

適配器實作:統一介面

<?php
// 1. 定義統一介面 (既有代碼依賴此介面)
interface HelloWorldInterface {
    public function sayHello(): string;
    public function sayWorld(): string;
}

// 2. 適配器:包裝 V1
class HwLibV1Adapter implements HelloWorldInterface {
    private HwLibV1 $lib;
    
    public function __construct(HwLibV1 $lib) {
        $this->lib = $lib;
    }
    
    public function sayHello(): string {
        return $this->lib->hello();
    }
    
    public function sayWorld(): string {
        return $this->lib->world();
    }
}

// 3. 適配器:包裝 V2 (介面轉換)
class HwLibV2Adapter implements HelloWorldInterface {
    private HwLibV2 $lib;
    
    public function __construct(HwLibV2 $lib) {
        $this->lib = $lib;
    }
    
    public function sayHello(): string {
        return $this->lib->greet(); // 關鍵:映射 greet() → sayHello()
    }
    
    public function sayWorld(): string {
        return $this->lib->world();
    }
}

// 4. 工廠:根據版本自動選擇適配器
class HelloWorldFactory {
    public static function create(string $version = 'v2'): HelloWorldInterface {
        return match($version) {
            'v1' => new HwLibV1Adapter(new HwLibV1()),
            'v2' => new HwLibV2Adapter(new HwLibV2()),
            default => throw new InvalidArgumentException("Unknown version: $version"),
        };
    }
}

// 5. 客戶端代碼完全不變
$hw = HelloWorldFactory::create('v2'); // 或從配置讀取
echo $hw->sayHello() . $hw->sayWorld(); // "Greetings and Salutations World!"
?>

進階:雙向適配器 (雙重介面)

<?php
// 新系統使用新介面,舊系統使用舊介面,適配器同時實作兩者
class DualAdapter implements HelloWorldInterface, NewSystemInterface {
    private HwLibV2 $lib;
    
    public function __construct(HwLibV2 $lib) { $this->lib = $lib; }
    
    // 舊介面
    public function sayHello(): string { return $this->lib->greet(); }
    public function sayWorld(): string { return $this->lib->world(); }
    
    // 新介面
    public function greetFormally(): string { return $this->lib->greet(); }
    public function getPlanet(): string { return $this->lib->world(); }
}
?>

適配器 vs 代理 vs 裝飾器 比較

模式 目的 介面關係 典型用途
適配器 介面轉換 目標介面 ≠ 來源介面 第三方庫整合、舊系統遷移、API 版本兼容
代理 控制存取 目標介面 = 來源介面 延遲載入、權限控制、遠程代理、快取
裝飾器 動態增強 目標介面 = 來源介面 (可擴展) 功能疊加、I/O 流處理、中介軟體

實戰:資料庫驅動適配器

<?php
// 統一資料庫介面
interface DatabaseAdapter {
    public function connect(array $config): void;
    public function query(string $sql): iterable;
    public function execute(string $sql): int;
    public function lastInsertId(): string;
    public function beginTransaction(): void;
    public function commit(): void;
    public function rollBack(): void;
}

// MySQL 適配器
class MySQLAdapter implements DatabaseAdapter {
    private PDO $pdo;
    
    public function connect(array $config): void {
        $dsn = "mysql:host={$config['host']};dbname={$config['dbname']};charset=utf8mb4";
        $this->pdo = new PDO($dsn, $config['user'], $config['pass'], [
            PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
            PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
        ]);
    }
    
    public function query(string $sql): iterable {
        return $this->pdo->query($sql);
    }
    // ... 其他方法委派給 PDO
}

// PostgreSQL 適配器
class PostgreSQLAdapter implements DatabaseAdapter {
    private PDO $pdo;
    public function connect(array $config): void {
        $dsn = "pgsql:host={$config['host']};dbname={$config['dbname']}";
        $this->pdo = new PDO($dsn, $config['user'], $config['pass']);
    }
    // ... 相同介面,不同實作
}

// SQLite 適配器
class SQLiteAdapter implements DatabaseAdapter {
    private PDO $pdo;
    public function connect(array $config): void {
        $this->pdo = new PDO("sqlite:{$config['path']}");
    }
    // ...
}

// 使用:配置驅動切換
$config = parse_ini_file('database.ini'); // driver=mysql
$adapterClass = match($config['driver']) {
    'mysql'      => MySQLAdapter::class,
    'postgresql' => PostgreSQLAdapter::class,
    'sqlite'     => SQLiteAdapter::class,
};
$db = new $adapterClass();
$db->connect($config);
foreach ($db->query("SELECT * FROM users") as $user) { /* ... */ }
?>

適配器模式最佳實踐

  • ✅ 介面隔離:定義精簡、穩定的目標介面
  • ✅ 單一職責:適配器只做轉換,不包含業務邏輯
  • ✅ 工廠封裝:用工廠隱藏具體適配器建立細節
  • ✅ 測試友善:易於 Mock 目標介面進行單元測試
  • ⚠️ 避免過度:介面相容時無需適配器,直接使用
  • ⚠️ 效能考量:極高頻呼叫的熱路徑可能引入微小開銷
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved