Adapter Pattern,PHP 適配器模式

目錄
簡介
什麼是 Adapter Pattern
Adapter Pattern(適配器模式)是一種結構型設計模式,用於讓兩個不相容的介面能夠協同工作。透過建立一個額外的類別(適配器),將一個介面轉換為另一個客戶端期望的介面,就像電器轉接頭一樣,讓不同規格的插頭能夠使用同一個插座。
什麼狀況適合使用 Adapter Pattern
- 整合舊系統:系統需要使用現有的類別,但其介面不符合系統需求。
- 整合第三方套件:要整合多個不同的函式庫或 API,它們有不同的介面或資料格式。
- 重用遺留程式碼:需要重用一些遺留程式碼,但不希望修改原有的介面或程式碼,以保持系統的穩定性。
- 統一介面:希望統一多個不同來源的類別,讓它們使用相同的介面進行操作。
範例教學
我們以一個咖啡機為例來說明 Adapter Pattern 的應用。假設我們有一個舊式咖啡機,它使用的介面與我們新系統不相容。在這種情況下,我們可以使用 Adapter Pattern 來解決這個問題,讓舊式咖啡機能夠無縫整合到新系統中。
原始程式,未使用 Adapter
<?php
// 舊式咖啡機
class OldCoffeeMachine {
public function makeOldStyleCoffee() {
return "Making coffee the old-fashioned way.";
}
}
// 新系統
class CoffeeMaker {
public function brew() {
return "Brewing coffee with the new machine.";
}
}
$oldMachine = new OldCoffeeMachine();
echo $oldMachine->makeOldStyleCoffee(); // 輸出: Making coffee the old-fashioned way.
$newMachine = new CoffeeMaker();
echo $newMachine->brew(); // 輸出: Brewing coffee with the new machine.
?>這樣的作法有明顯的缺點:無法直接在新系統中使用 OldCoffeeMachine,因為介面不匹配。如果要整合,就必須修改舊有的程式碼,或者撰寫額外的程式碼來處理介面轉換,這不僅增加了維護成本,也可能影響原有系統的穩定性。
改善範例,使用 Adapter
<?php
// Adapter
class CoffeeMachineAdapter {
private $oldMachine;
public function __construct(OldCoffeeMachine $oldMachine) {
$this->oldMachine = $oldMachine;
}
public function brew() {
return $this->oldMachine->makeOldStyleCoffee();
}
}
$oldMachine = new OldCoffeeMachine();
$adapter = new CoffeeMachineAdapter($oldMachine);
echo $adapter->brew(); // 輸出: Making coffee the old-fashioned way.
?>透過 Adapter Pattern,我們能夠無縫地整合舊有系統和新系統,無需修改原有類別。無論是新系統還是舊系統,都可以使用相同的 brew() 介面來操作,這樣就實現了介面的統一,讓程式碼更加一致且易於維護。
更多延伸範例
接下來,我們來看一個更複雜的範例,展示多種類型的咖啡機和對應的適配器。這個範例可以幫助我們更清楚地觀察 Adapter Pattern 的優勢,以及需要注意的地方。
<?php
// 舊式咖啡機
class OldCoffeeMachine {
public function makeOldStyleCoffee() {
return "Making coffee the old-fashioned way.";
}
}
// Espresso 咖啡機
class EspressoMachine {
public function makeEspresso() {
return "Making an espresso.";
}
}
// Mocha 咖啡機
class MochaMachine {
public function makeMocha() {
return "Making a Mocha coffee.";
}
}
// Adapter for OldCoffeeMachine
class OldMachineAdapter {
private $machine;
public function __construct(OldCoffeeMachine $machine) {
$this->machine = $machine;
}
public function brew() {
return $this->machine->makeOldStyleCoffee();
}
}
// Adapter for EspressoMachine
class EspressoMachineAdapter {
private $machine;
public function __construct(EspressoMachine $machine) {
$this->machine = $machine;
}
public function brew() {
return $this->machine->makeEspresso();
}
}
// Adapter for MochaMachine
class MochaMachineAdapter {
private $machine;
public function __construct(MochaMachine $machine) {
$this->machine = $machine;
}
public function brew() {
return $this->machine->makeMocha();
}
}
// 使用
$oldMachine = new OldCoffeeMachine();
$oldMachineAdapter = new OldMachineAdapter($oldMachine);
echo $oldMachineAdapter->brew(); // 輸出: Making coffee the old-fashioned way.
$espressoMachine = new EspressoMachine();
$espressoAdapter = new EspressoMachineAdapter($espressoMachine);
echo $espressoAdapter->brew(); // 輸出: Making an espresso.
$mochaMachine = new MochaMachine();
$mochaAdapter = new MochaMachineAdapter($mochaMachine);
echo $mochaAdapter->brew(); // 輸出: Making a Mocha coffee.
?>透過使用適配器模式,我們能夠輕易地為不同類型的咖啡機建立適配器,並使它們能與我們的新系統無縫地整合。每一種咖啡機都有對應的適配器,將各自的方法轉換為統一的 brew() 介面。
這種方式也讓未來的擴展變得非常容易。如果有新類型的咖啡機出現,只需要為其建立一個新的適配器類別即可,完全不需要修改現有的程式碼。這樣,無論咖啡機如何升級或更換,我們的主程式碼都不需要做任何改動,這正是適配器模式的核心優勢:開閉原則(Open-Closed Principle)——對擴展開放,對修改封閉。
Adapter Pattern 的優缺點
優點:
- 讓不相容的介面能夠協同工作,無需修改原有類別
- 提高了程式碼的重用性和靈活性
- 符合單一職責原則,適配器只負責介面轉換
- 符合開閉原則,易於擴展新功能
缺點:
- 增加程式碼複雜度,需要額外的適配器類別
- 如果介面差異太大,適配器可能會變得複雜
- 過度使用可能會讓程式碼結構變得難以理解
其他類似的 Design Pattern
在設計模式中,有幾個與 Adapter Pattern 相似的模式,但它們的用途和應用場景有所不同:
- Facade Pattern(外觀模式):隱藏系統的複雜性,提供一個統一的簡化介面。Facade 通常用於簡化複雜子系統的介面,而 Adapter 則用於讓不相容的介面能夠協同工作。
- Bridge Pattern(橋接模式):分離一個物件的抽象和實現,使兩者可以獨立地變化。Bridge 著重於解耦抽象與實現,而 Adapter 著重於介面轉換。
- Decorator Pattern(裝飾器模式):動態地為物件添加功能,而 Adapter 則是轉換介面而不改變功能。
主要差異:
- Adapter:將一個介面轉換成另一個介面,讓不相容的類別能夠協同工作
- Facade:提供一個簡化的統一介面來隱藏複雜的子系統
- Bridge:分離抽象和實現,讓它們可以獨立變化
實際應用場景
Adapter Pattern 在實際開發中經常被使用,常見的應用場景包括:
- API 整合:整合不同版本的 API 或第三方服務,統一它們的呼叫方式
- 資料庫抽象層:將不同資料庫的介面統一,例如 PDO 就是一個很好的例子
- 第三方函式庫整合:整合不同來源的函式庫,讓它們使用統一的介面
- 舊系統遷移:在系統重構時,讓舊的類別能夠在新系統中繼續使用
總結
Adapter Pattern 是一個非常實用的設計模式,特別適合在需要整合不相容介面的情況下使用。透過建立適配器類別,我們可以讓舊系統和新系統、不同來源的函式庫或 API 能夠無縫協同工作,同時保持程式碼的整潔和可維護性。
記住,適配器模式的核心思想是「轉換介面,而非改變功能」,這讓我們能夠在不修改原有程式碼的情況下,實現系統的整合和擴展。
參考來源
- "Design Patterns: Elements of Reusable Object-Oriented Software" by Erich Gamma, Richard Helm, Ralph Johnson, and John Vlissides
- PHP: The Right Way
- Refactoring.Guru - Adapter Pattern
- ← Previous
Decorator Pattern,PHP 裝飾者模式 - Next →
Observer Pattern,PHP 觀察者模式



