在本系列中,我將介紹 PHP 物件導向程式設計 (OOP) 的基礎知識。內容將被組織成連續的部分,每個部分都專注於一個特定的主題。如果您是初學者或不熟悉 OOP 概念,本系列旨在逐步指導您。 在這一部分中,我將討論 PHP 中的組合與繼承和依賴注入。讓我們一起開始學習PHP OOP的旅程吧!
我們已經了解了物件導向程式設計中父類別和子類別之間的關係,我們看到子類別可以繼承父類別並存取父類別的所有內容。這就是所謂的繼承。
另一方面,組合是指將父類別指派為子類別中的屬性值,而不是繼承它。透過這個,我們可以存取父類別的所有內容。這稱為組合。
以下是說明組合和繼承的範例。
class Link { public string $name; public string $type; public function create($name, $type) { $this->name = $name; $this->type = $type; } public function show() { echo "name: $this->name, type: $this->type"; } } // Inheritance example class ShoLink extends Link { // other functionalities } // Composition example class User { public Link $link; public function __construct() { $this->link = new Link(); } // other functionalities } $user = new User(); $user->link->create("Jamir", "Short");
在第一個範例中,我們可以看到 ShoLink 類別繼承了 Link 類別。另一方面,在第二個範例中,User 類別沒有繼承 Link 類別。相反,它將 Link 類別的一個實例分配給它的屬性之一。因此,我們可以存取兩個子類別中 Link 類別的所有內容。
現在可能會出現一個問題:如果我們已經可以透過繼承來存取所有內容,為什麼還要使用組合呢?畢竟,對於組合,我們需要聲明一個附加屬性並透過構造來設定其值。這看起來像是額外的工作——那麼使用組合有什麼好處呢?
嗯,我們知道繼承使得父類別中的所有內容都可以在子類別中存取。因此,即使我們不想使用父類別的某些方法,或者子類別中不需要父類別的某些屬性或方法,如果它們是公共或受保護成員,它們仍然可以在子類別中存取.
為了解決這個問題,使用了組合。透過組合,我們可以只讓子類別可以存取父類別所需的部分。讓我們用另一個例子進一步闡明這一點。
如果我們仔細觀察 Link 類,我們可以看到它有一個 show 方法。使用這個方法,我們可以直接顯示ShoLink類別中建立的連結。
但是,如果我們希望 User 類別阻止任何人直接查看為使用者建立的連結怎麼辦?相反,我們可能希望在用戶的個人資料旁邊顯示用戶的連結。
這就是為什麼在 User 類別中,我們不是繼承 Link 類,而是透過組合來存取它。這樣一來,沒有人可以透過 User 類別直接查看使用者的鏈接,但可以直接查看 ShoLink 類別的連結。
現在我們對組合以及何時使用組合而不是繼承來解決某些問題有了一些了解。在OOP中,有一個原則叫做“Favor Composition over Inheritance”,意思是組合優先於繼承。換句話說,對於不需要從父類存取所有內容的子類,我們應該始終優先選擇組合而不是繼承。
現在問題來了:我們如何決定何時使用組合以及何時使用繼承?
在這種情況下,我們需要根據兩種類型的關係來做決定:
class Link { public string $name; public string $type; public function create($name, $type) { $this->name = $name; $this->type = $type; } public function show() { echo "name: $this->name, type: $this->type"; } } // Inheritance example class ShoLink extends Link { // other functionalities } // Composition example class User { public Link $link; public function __construct() { $this->link = new Link(); } // other functionalities } $user = new User(); $user->link->create("Jamir", "Short");
如果您查看上面 ShoLink 類別的範例,您會發現 ShoLink 類別繼承自 Link 類別。因此,如果我要定義它們之間的關係,則該關係將是 ShoLink 是鏈接,因為 ShoLink 本質上是鏈結的一種類型。
// Inheritance example class ShoLink extends Link { // other functionalities }
現在,如果我們看一下上面 User 類別的範例,我們可以看到 User 類別與 Link 類別使用組合。因此,如果我要定義它們之間的關係,則該關係將是“用戶擁有鏈接”,因為用戶不是鏈接,但用戶可以擁有鏈接或可能擁有鏈接。
我希望您現在對組合和繼承有了更清晰的了解,包括何時使用每一項以及在不同情況下優先考慮哪一項。
在了解依賴注入之前,我們首先需要了解什麼是依賴。依賴是指子類別透過繼承或組合使用另一個類別的成員。在這種情況下,父類別將成為子類別的依賴項。
在上面的例子中,我們看到當我們使用組合而不是繼承時,我們需要在子類別中聲明一個屬性,並透過建構子將父類別的實例分配給該屬性。因此,如果我們要使用User類,就必須在其建構子中實例化Link類,因為User類別依賴Link類別。換句話說,Link 類別是 User 類別的依賴項。這裡的問題是 Link 類別的實例化過程與 User 類別緊密耦合。
問題在於 Link 類別的實例化是有限的並且特定於 User 類別。如果我們想將任何其他類別而不是 Link 類別從外部傳遞到 User 類別中,我們就不能這樣做,因為我們在建構函數中明確建立 Link 類別的實例並將其指派給 Link 屬性。這稱為緊密耦合依賴關係,意味著我們無法從外部更改此依賴關係。
但是,如果我們不在建構函式中自己實例化Link 類,而是將其留給用戶,這意味著當用戶使用我們的User 類別時,他們會將Link 類別相依性傳遞給User 類,我們的問題將是解決了。
讓我們來看看下面的程式碼範例。
class Link { public string $name; public string $type; public function create($name, $type) { $this->name = $name; $this->type = $type; } public function show() { echo "name: $this->name, type: $this->type"; } } // Inheritance example class ShoLink extends Link { // other functionalities } // Composition example class User { public Link $link; public function __construct() { $this->link = new Link(); } // other functionalities } $user = new User(); $user->link->create("Jamir", "Short");
在此範例中,我們可以看到,我們不是在 User 類別的建構子中實例化 Link 類,而是從外部將 Link 類別的相依性傳遞到 User 類別中。這種透過使用者將相依性傳遞到 User 類別的過程稱為相依性注入。換句話說,我們從外部注入或推送 Link 類別的依賴項。這稱為松耦合依賴關係,這意味著我們可以輕鬆地從外部更改此依賴關係。
現在,如果 Link 類別也有自己的依賴項,我們也可以透過 User 類別從外部將這些依賴項注入到它中。然後,我們可以簡單地將 Link 類別的實例注入到 User 類別中。因此,我們不需要擔心 Link 類別在 User 類別中的依賴關係,因為使用者將從外部處理它。
讓我們來看看下面的程式碼範例。
// Inheritance example class ShoLink extends Link { // other functionalities }
這樣我們就可以從外部注入任意數量的依賴,而且會靈活很多。這就是今天的全部內容;我們下節課再講。
您可以在 GitHub 和 Linkedin 上與我聯絡。
以上是PHP OOP 部分組合與繼承和依賴注入的詳細內容。更多資訊請關注PHP中文網其他相關文章!