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

PHP 設計模式系列:觀察者模式實戰解耦業務邏輯

     編輯:PHP 相關知識

模式動機

觀察者模式定義物件間的一對多依賴,當一個物件(主題/Subject)狀態改變時,所有依賴它的物件(觀察者/Observer)都會收到通知並自動更新。在複雜 Web 系統中,它能有效分離核心業務與副作用邏輯(如發送郵件、日誌記錄、狀態同步),大幅降低耦合度。

訂單系統場景演示

訂單創建後需觸發:發送確認郵件、更新庫存、記錄操作日誌、通知倉儲系統等。傳統寫法將所有邏輯塞入 create() 方法,導致類膨脹、難以擴展、單元測試困難。

核心代碼實現

<?php
class Order {
    protected $observers = []; // 觀察者容器:['event_type' => [ObserverClass1, ObserverClass2, ...]]

    // 註冊觀察者
    public function addObserver($eventType, $observerClass) {
        $this->observers[$eventType][] = $observerClass;
    }

    // 觸發通知
    protected function notifyObservers($eventType) {
        if (isset($this->observers[$eventType])) {
            foreach ($this->observers[$eventType] as $observerClass) {
                $observer = new $observerClass();
                $observer->update($this); // 統一調用 update() 方法
            }
        }
    }

    // 核心業務邏輯
    public function create() {
        echo "購買成功\n";
        // 業務邏輯:保存訂單、扣減庫存等...
        $this->notifyObservers('order_created'); // 觸發事件
    }
}

// 觀察者實現:發送郵件
class OrderEmailObserver {
    public function update(Order $order) {
        echo "發送購買成功郵件通知\n";
        // Mail::to($order->user->email)->send(new OrderCreated($order));
    }
}

// 觀察者實現:更新訂單狀態
class OrderStatusObserver {
    public function update(Order $order) {
        echo "更新訂單狀態為:已確認\n";
        // $order->status = 'confirmed'; $order->save();
    }
}

// 觀察者實現:記錄操作日誌
class OrderLogObserver {
    public function update(Order $order) {
        echo "記錄操作日誌:訂單 {$order->id} 創建\n";
        // Log::info('Order created', ['order_id' => $order->id]);
    }
}

// 使用示例
$order = new Order();
$order->addObserver('order_created', OrderEmailObserver::class);
$order->addObserver('order_created', OrderStatusObserver::class);
$order->addObserver('order_created', OrderLogObserver::class);
$order->create();

進階優化方向

1. 引入觀察者介面強制契約

interface ObserverInterface {
    public function update($subject);
}

class OrderEmailObserver implements ObserverInterface { ... }

2. 支持優先級與停止傳播

$this->observers[$eventType][] = ['class' => $cls, 'priority' => 10];
// 觸發時按優先級排序,觀察者可返回 false 停止後續傳播

3. 使用 PHP 內建 SplSubject/SplObserver(SPL 標準庫)


class Order extends SplSubject {
    // 實現 attach, detach, notify
}
class EmailObserver implements SplObserver {
    public function update(SplSubject $subject) { ... }
}

4. 異步處理:將觀察者推送到消息隊列


public function notifyObservers($eventType) {
    foreach ($this->observers[$eventType] as $observerClass) {
        // 同步:輕量級觀察者直接執行
        // 異步:重型任務推送到隊列
        if (in_array($observerClass, $this->asyncObservers)) {
            Queue::push(new ProcessObserver($observerClass, $this->id));
        } else {
            (new $observerClass())->update($this);
        }
    }
}

優缺點總結

優點缺點
主題與觀察者解耦,符合單一職責原則觀察者過多時通知鏈長,影響響應時間
動態添加/移除觀察者,無需修改主題代碼循環引用風險(需弱引用或手動 detach)
支持開閉原則,新增觀察者零侵入異步場景下一致性難以保證(需事件溯源/補償)
便於單元測試(Mock 觀察者)調試困難:調用鏈隱式,需日誌追蹤

適用場景判斷清單

  • ✅ 一個操作觸發多個獨立副作用
  • ✅ 副作用邏輯頻繁變更/擴展
  • ✅ 核心業務不應依賴具體副作用實現
  • ❌ 簡單 CRUD、無副作用場景
  • ❌ 強一致性事務場景(用事件溯源/ Saga 模式)
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved