1. 程式人生 > >PHP之AOP面向切面程式設計原理(高階1)

PHP之AOP面向切面程式設計原理(高階1)

我們以一個簡單的留言板程式碼為例,先來看一個最簡單的三層結構程式碼,如程式碼1所示:

複製程式碼 // 程式碼 1
//
外觀層類class LWordHomePage {
// 新增留言publicfunction append($newLWord) {
// 呼叫中間服務層$serv=new LWordServiceCore();
$serv->append($newLWord);
}
};

// 中間服務層class LWordServiceCore {
// 新增留言publicfunction append($newLWord) {
// 呼叫資料訪問層$dbTask=new LWordDBTask();
$dbTask->
append($newLWord);
}
};

// 資料訪問層class LWordDBTask {
// 新增留言publicfunction append($newLWord) {
// 資料層程式碼(省略) }
};
複製程式碼

 執行時序圖,如圖1所示:

(圖1),簡單三層結構時序圖

從程式碼和時序圖中可以直觀看出三層結構的呼叫順序。但實際開發中這種簡單三層結構並不能滿足需求!我們先從外觀層與中間服務層這兩層的程式碼開始討論。在外觀層LWordHomePage類中直接使用new關鍵字建立並呼叫中間服務類LWordServiceCore屬於一種硬編碼的方式。在實際專案開發過程中,外觀層和中間服務層可能會由不同的人員來開發,即一個功能模組由多個人共同完成。而外觀層LWordHomePage類的開發進度是不可能等到LWordServiceCore類完全開發完成之後才開始(換句話來說就是,外觀層不可能等到中間服務層完全開發完成之後才開始),這樣的協作效率非常低!

為了使專案可以由多人同時開發,所以我們要切割程式碼設計。我們可以組織一個臨時的中間服務類來滿足外觀層的開發進度。等到中間服務層完全開發完成之後,替換一下就可以了……如圖2所示:

 

(圖2),外觀層在不同的服務間切換

顯然,要實現這樣的需求,在外觀層中直接使用new關鍵字建立和呼叫LWordServiceCore類是非常不靈活的!這很難做到靈活的隨意的切換!!我們可以建立TempService類充當中間服務層的臨時實現。我們還需要分析一下TempService和LWordServiceCore這兩個類,它們都具備相同的append函式用於新增留言,只不過一個是臨時的而另外一個是真實的。既然TempService和LWordServiceCore這兩個類都有公共函式,那麼就應該可以有一個公共的父類。考慮到對這個公共的上級類沒有別的成員和屬性,所以將這個公共的上級類定義為介面,即ILWordService!UML類圖如圖3所示:

 

(圖3)定義和實現ILWordService介面

在LWordHomePage類中並不直接建立TempService或者LWordServiceCore類物件,建立過程會交給一個工廠類MyServiceFactory(簡單工廠模式)。這樣一來,外觀層中的LWordHomePage類只需要知道ILWordService介面即可,外觀層程式碼並不關心具體的中間服務程式碼是什麼,這樣就極好的實現了外觀層與具體服務程式碼的分離。

這相當於什麼呢?就好比兩個硬體工程師,一個是製造計算機顯示卡的,一個是製造計算機主機板的。製造顯示卡的工程師可以把顯示卡插到到一塊測試電路中,來測試顯示卡是否可以正常工作?同樣,製造主機板的工程師也可以把主機板插入到另一塊測試電路中,來測試主機板是否可以正常工作?等到這兩位工程師都各自完成工作之後,將他倆的工作成果對接在一起就可以了。這是一種並行開發方式,幾乎可以省掉一半的時間。從軟體工程的角度來講,我們在設計介面程式碼的時候也應該考慮是否需要支援多人同時開發,從而提高生產效率。

依照UML類圖(如圖3所示),我們修改PHP程式碼如程式碼2所示:

複製程式碼 // 程式碼2, 通過工廠建立留言服務並呼叫
// 外觀層類class LWordHomePage {
// 新增留言publicfunction append($newLWord) {
// 呼叫中間服務$serv= MyServiceFactory::create();
// 注意此時是操作 ILWordService 介面, 而非 LWordService 類$serv->append($newLWord
);
}
};

// 留言服務介面interface ILWordService {
publicfunction append($newLWord);
};

// 服務工廠類class MyServiceFactory {
// 建立留言服務publicstaticfunction create() {
if (1) {
// 返回中間服務層returnnew LWordServiceCore();
}
else {
// 返回臨時實現returnnew
TempService();
}
}
}


// 臨時服務類class TempService implements ILWordService {
// 新增留言publicfunction append($newLWord) {
// 臨時程式碼(省略) }
};

// 中間服務層class LWordServiceCore implements ILWordService {
// 新增留言publicfunction append($newLWord) {
// 呼叫資料訪問層$dbTask=new LWordDBTask();
$dbTask->append($newLWord);
}
};

// 資料訪問層class LWordDBTask {
// 新增留言publicfunction append($newLWord) {
// 資料層程式碼(省略) }
};
複製程式碼

時序圖如圖4所示:

(圖4)通過工廠類建立留言服務