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

PHP 經典面試題:單例、工廠、組合、策略四大設計模式完整實作與應用場景解析

     編輯:PHP 綜合知識

前言

設計模式是面試必考、重構利器。本文精選 PHP 開發最高頻的 **單例、工廠、組合、策略** 四大模式,提供可直接執行的完整代碼、UML 關係說明與實戰應用場景。

1. 單例模式 — 確保全域唯一實例

核心要素

  • 私有建構子 private __construct()
  • 私有克隆 private __clone()
  • 靜態實例屬性 private static $instance
  • 公開靜態取得方法 public static getInstance()

經典場景:PDO 資料庫連線

class SinglePDO {
    private static ?self $_instance = null;
    private PDO $_pdo;
    
    private function __construct(string $dsn, string $user, string $pass) {
        try {
            $this->_pdo = new PDO($dsn, $user, $pass);
            $this->_pdo->exec('SET NAMES utf8mb4');
            $this->_pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
        } catch (PDOException $e) {
            die("DB Connect Failed: {$e->getMessage()}");
        }
    }
    
    private function __clone() {} // 禁止克隆
    
    public static function getInstance(string $dsn, string $user, string $pass): self {
        if (self::$_instance === null) {
            self::$_instance = new self($dsn, $user, $pass);
        }
        return self::$_instance;
    }
    
    public function execute(string $sql): int|false {
        return $this->_pdo->exec($sql);
    }
    
    public function query(string $sql): PDOStatement {
        return $this->_pdo->query($sql);
    }
}

// 使用
$pdo = SinglePDO::getInstance('mysql:host=localhost;dbname=test', 'root', '');
$pdo->execute("DELETE FROM user WHERE id = 1");

進階:多實例單例(Multiton)

支援多組不同 DSN 連線:

class MultiPDO {
    private static array $instances = [];
    
    private function __construct(private string $dsn, private string $user, private string $pass) {}
    
    public static function getInstance(string $dsn, string $user, string $pass): self {
        $key = md5($dsn . $user);
        if (!isset(self::$instances[$key])) {
            self::$instances[$key] = new self($dsn, $user, $pass);
        }
        return self::$instances[$key];
    }
}

2. 工廠模式 — 封裝物件建立邏輯

簡單工廠

interface PaymentGateway {
    public function pay(float $amount): bool;
}

class Alipay implements PaymentGateway { public function pay(float $amount): bool { /* ... */ return true; } }
class WechatPay implements PaymentGateway { public function pay(float $amount): bool { /* ... */ return true; } }

class PaymentFactory {
    public static function create(string $type): PaymentGateway {
        return match ($type) {
            'alipay' => new Alipay(),
            'wechat' => new WechatPay(),
            default => throw new InvalidArgumentException("Unknown gateway: $type"),
        };
    }
}

// 使用
$gateway = PaymentFactory::create('alipay');
$gateway->pay(99.00);

工廠方法(擴充性更強)

abstract class PaymentFactoryBase {
    abstract protected function createGateway(): PaymentGateway;
    
    public function processPayment(float $amount): bool {
        $gateway = $this->createGateway();
        return $gateway->pay($amount);
    }
}

class AlipayFactory extends PaymentFactoryBase {
    protected function createGateway(): PaymentGateway { return new Alipay(); }
}

3. 組合模式 — 樹形結構統一介面

場景:目錄/檔案、選單/子選單、組織架構

interface FileSystemComponent {
    public function getName(): string;
    public function getSize(): int;
    public function display(int $depth = 0): void;
}

class File implements FileSystemComponent {
    public function __construct(private string $name, private int $size) {}
    public function getName(): string { return $this->name; }
    public function getSize(): int { return $this->size; }
    public function display(int $depth = 0): void {
        echo str_repeat('  ', $depth) . "📄 {$this->name} ({$this->size} KB)" . PHP_EOL;
    }
}

class Directory implements FileSystemComponent {
    private array $children = [];
    
    public function __construct(private string $name) {}
    
    public function add(FileSystemComponent $component): void {
        $this->children[] = $component;
    }
    
    public function getName(): string { return $this->name; }
    public function getSize(): int {
        return array_reduce($this->children, fn($sum, $c) => $sum + $c->getSize(), 0);
    }
    
    public function display(int $depth = 0): void {
        echo str_repeat('  ', $depth) . "📁 {$this->name}" . PHP_EOL;
        foreach ($this->children as $child) {
            $child->display($depth + 1);
        }
    }
}

// 使用
$root = new Directory('root');
$root->add(new File('index.php', 10));
$src = new Directory('src');
$src->add(new File('User.php', 5));
$src->add(new File('Post.php', 8));
$root->add($src);
$root->display();

4. 策略模式 — 演算法族群熱插拔

場景:排序、壓縮、付款、驗證、匯出格式

interface SortStrategy {
    public function sort(array $data): array;
}

class BubbleSort implements SortStrategy {
    public function sort(array $data): array {
        // 簡化示意
        sort($data);
        return $data;
    }
}

class QuickSort implements SortStrategy {
    public function sort(array $data): array {
        // 簡化示意
        sort($data, SORT_NUMERIC);
        return $data;
    }
}

class SortContext {
    public function __construct(private SortStrategy $strategy) {}
    
    public function setStrategy(SortStrategy $strategy): void {
        $this->strategy = $strategy;
    }
    
    public function execute(array $data): array {
        return $this->strategy->sort($data);
    }
}

// 使用
$context = new SortContext(new QuickSort());
$sorted = $context->execute([3,1,4,1,5,9]);
$context->setStrategy(new BubbleSort());
$sorted = $context->execute(['c','a','b']);

四大模式對比速查

模式核心目的關鍵結構典型應用
單例全域唯一存取點私有建構子 + 靜態實例DB連線、快取、日誌、配置
工廠解耦建立邏輯介面 + 多實作 + 工廠類支付閘道、驅動載入、文檔解析器
組合部分-整體樹形結構統一介面 + 遞歸組合選單、目錄、組織架構、AST
策略演算法可互換策略介面 + 多具體策略 + Context排序、壓縮、路由演算、驗證規則

面試加分點

  • 單例:說明 雙重檢查鎖定 在 PHP 單執行緒無需,但多進程(Swoole)需用 Redis/Memcached 分散式鎖
  • 工廠:提到 PSR-11 Container 可作為通用工廠
  • 組合:強調 遞歸深度 可能導致堆疊溢出,大樹結構改用迭代器
  • 策略:結合 Dependency Injection 由容器注入策略,達成開閉原則

總結

掌握這四大模式,即能應對 80% 以上的 PHP 面試設計模式題目,更能在重構舊代碼時游刃有餘。記住:**模式是為了解決具體問題而生,不要為了用模式而用模式。**

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved