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

Head First 設計模式:策略模式 PHP 實作與組合優於繼承原則

     編輯:PHP 相關知識

策略模式定義演算法家族,分別封裝並使其可互換,讓演算法變化獨立於使用演算法的客戶端。本文以鴨子模擬器為例,展示飛行行為 (FlyBehavior) 與叫聲行為 (QuackBehavior) 策略介面及其多種實作,透過組合方式注入鴨子類別,實現執行時動態切換行為,深度體現「多用組合、少用繼承」設計原則。

策略介面定義

<?php
// 飛行行為介面
interface FlyBehavior {
    public function fly();
}

// 叫聲行為介面
interface QuackBehavior {
    public function quack();
}
?>

具體策略實作

{// 飛行策略實作
class FlyWithWings implements FlyBehavior {
    public function fly() { echo "I'm flying!\n"; }
}

class FlyNoWay implements FlyBehavior {
    public function fly() { echo "I can't fly.\n"; }
}

class FlyRocketPowered implements FlyBehavior {
    public function fly() { echo "I'm flying with a rocket!\n"; }
}

// 叫聲策略實作
class Quack implements QuackBehavior {
    public function quack() { echo "Quack!\n"; }
}

class MuteQuack implements QuackBehavior {
    public function quack() { echo "Silence\n"; }
}

鴨子抽象基類 (組合策略)

abstract class Duck {
    protected $flyBehavior;
    protected $quackBehavior;

    public function __construct() {}

    // 委派給策略物件執行
    public function performFly() {
        $this->flyBehavior->fly();
    }

    public function performQuack() {
        $this->quackBehavior->quack();
    }

    // 執行時動態切換策略
    public function setFlyBehavior(FlyBehavior $fb) {
        $this->flyBehavior = $fb;
    }

    public function setQuackBehavior(QuackBehavior $qb) {
        $this->quackBehavior = $qb;
    }

    public function swim() {
        echo "All ducks float, even decoys!\n";
    }

    // 子類必須實作顯示外觀
    abstract public function display();
}

具體鴨子:綠頭鴨

class MallardDuck extends Duck {
    public function __construct() {
        // 預設策略:不會飛、普通叫聲
        $this->quackBehavior = new Quack();
        $this->flyBehavior = new FlyNoWay();
    }

    public function display() {
        echo "I'm a real Mallard duck\n";
    }
}

客戶端測試:動態切換飛行策略

<?php
require_once 'Duck.php';
require_once 'MallardDuck.php';
require_once 'FlyBehavior.php';
require_once 'FlyWithWings.php';
require_once 'FlyNoWay.php';
require_once 'FlyRocketPowered.php';

$duck = new MallardDuck();
$duck->display();           // I'm a real Mallard duck
$duck->performFly();        // I can't fly. (預設 FlyNoWay)

// 執行時動態改變行為:裝上火箭推進器!
$duck->setFlyBehavior(new FlyRocketPowered());
$duck->performFly();        // I'm flying with a rocket!
?>

輸出結果

I'm a real Mallard duck
I can't fly.
I'm flying with a rocket!

策略模式核心優勢

優勢說明本例體現
演算法封裝每個策略類別封裝單一演算法變體FlyWithWings/FlyNoWay/FlyRocketPowered 分別封裝不同飛行邏輯
可互換相同介面策略可自由替換setFlyBehavior() 任意切換飛行策略
獨立變化新增策略不修改客戶端 (Duck)新增 FlyJetPowered 只需實作 FlyBehavior,Duck 完全不用動
執行時切換物件生命週期中可動態改變行為$duck->setFlyBehavior(new FlyRocketPowered()) 即時生效
避免繼承爆炸不用為每種組合建立子類不需 MallardDuckWithRocket、MallardDuckNoFly 等子類

設計原則:多用組合,少用繼承

  • 繼承缺點:靜態、編譯期決定、父類變更影響所有子類、單一繼承限制、組合爆炸
  • 組合優點:動態、執行期決定、鬆耦合、單一職責、靈活復用、支援多重行為組合
  • 本例對比:若用繼承,需建立 MallardDuck, MallardDuckWithRocket, RedheadDuck, RedheadDuckWithRocket... 類別數量 = 鴨子種類 × 飛行策略 × 叫聲策略,指數級增長。

適用場景

  1. 同一行為有多種演算法實作 (排序、壓縮、加密、路由、支付、匯出格式)
  2. 需要執行時動態切換演算法
  3. 想避免大量條件判斷 (if/else/switch 選擇演算法)
  4. 演算法邏輯頻繁變動或擴充

總結

策略模式透過 介面定義契約、具體類別封裝演算法、組合注入客戶端、執行時動態切換 四步驟,實現演算法與使用者解耦。核心代碼 setFlyBehavior(new FlyRocketPowered()) 生動展示「組合優於繼承」:鴨子不繼承飛行能力,而是擁有飛行策略物件。這是物件導向設計從「是一種」關係轉向「有一種」關係的經典範例。

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