設計模式是軟體工程的通用詞彙,掌握它們能讓代碼更具可複用性、可擴展性、可測試性。本文梳理 PHP 開發中最高頻的模式,結合原理、代碼骨架、應用場景。
核心: 私有構造函數、靜態實例屬性、公開靜態獲取方法。
class Database {
private static $instance = null;
private function __construct() { /* 連接 DB */ }
private function __clone() {} // 防止克隆
public static function getInstance() {
if (self::$instance === null) {
self::$instance = new self();
}
return self::$instance;
}
}
// 使用: $db = Database::getInstance();
場景: 資料庫連接、配置管理、日誌記錄器。注意: 單元測試難 Mock、隱式依賴、全局狀態污染,現代框架多改用依賴注入容器管理單例生命週期。
簡單工廠: 一個類根據參數決定創建哪個具體類。
class PaymentFactory {
public static function create($type) {
switch ($type) {
case 'alipay': return new AlipayPayment();
case 'wechat': return new WechatPayment();
default: throw new InvalidArgumentException('Unknown payment');
}
}
}
// 使用: $pay = PaymentFactory::create('alipay');
工廠方法/抽象工廠: 進一步解耦,符合開閉原則 (OCP),新增支付方式無需修改工廠代碼,只需擴展。框架中服務容器綁定接口到實現即是工廠思想體現。
類似 Registry 模式,提供 set(key, obj)/get(key) 存取任意對象,常與工廠配合緩存實例,避免重複創建。缺點: 全局狀態、隱式依賴,現代開發建議使用服務容器 (PSR-11)替代。
將不同第三方 SDK (如阿里云 OSS、騰訊云 COS、七牛云) 適配為統一 StorageInterface,業務代碼依賴接口而非具體實現,切換存儲商零成本。
場景: 根據用戶性別/等級/地區推送不同優惠策略、不同圖片壓縮算法、不同導出格式 (Excel/CSV/PDF)。
interface DiscountStrategy { public function calculate(float $amount): float; }
class VipDiscount implements DiscountStrategy { public function calculate($amt) { return $amt * 0.8; } }
class NewUserDiscount implements DiscountStrategy { public function calculate($amt) { return $amt - 50; } }
class OrderContext {
private $strategy;
public function setStrategy(DiscountStrategy $s) { $this->strategy = $s; }
public function getFinalPrice($amt) { return $this->strategy->calculate($amt); }
}
核心: Subject (被觀察者) 維護 Observer 列表,狀態變更時 notify() 遍歷調用 update()。
PHP 實踐: Symfony EventDispatcher、Laravel Events/Listeners、PSR-14 Event Dispatcher 標準。
場景: 訂單創建後發送郵件、扣庫存、記錄日誌、推送消息——各監聽器獨立開發、可插拔。
繼承的靈活替代方案。Decorator 實現同一接口,持有被裝飾對象引用,在調用前後添加邏輯 (日誌、緩存、權限、壓縮)。
interface Service { public function execute(); }
class CoreService implements Service { public function execute() { /* 核心邏輯 */ } }
class LoggingDecorator implements Service {
private $service;
public function __construct(Service $s) { $this->service = $s; }
public function execute() { Log::info('Start'); $this->service->execute(); Log::info('End'); }
}
實現 __clone() 魔術方法。適用於創建開銷大、狀態相似的對象 (如大型報表模板、複雜配置對象)。$newObj = clone $prototype;
深入理解這些模式,並在項目重構中嘗試引入,是邁向資深架構師的必經之路。