設計模式中依賴倒置原則(Dependence Inversion Principle
)的定義是“高層模組不應該依賴低層模組,二者都應該依賴其抽象;抽象不應該依賴細節;細節應該依賴抽象。”理解起來並不難,但在具體實現上,網上給出的很多PHP
示例都有缺陷。
就拿這篇文章來說,概念講的沒有問題,但在具體實現上,特別是程式碼中有很多錯誤,不能體現PHP
特色,比如PHP
中應該用->
而不是用.
來呼叫方法,變數名應該帶$
等很多錯誤,這就不說了,最關鍵的是即使把這些語法錯誤都改正,例子也不能說明原則,不夠有說服力。因為即使不加介面或抽象類,媽媽也一樣能給孩子講故事、讀報紙、讀雜誌。
以下可執行程式碼,沒有用到任何介面和抽象類,一樣可以實現功能,並且可擴充套件,不需要修改Mother
類裡的任何程式碼,一樣可以輕鬆自如地讓媽媽讀各種讀物,無非就是在上面追加各種class
,只要這個class
裡有getContent
方法,媽媽全部可以識別:
<?php
class Book {
public function getContent(){
return "很久很久以前有一個阿拉伯的故事……
";
}
}
class Newspaper {
public function getContent(){
return "林書豪17+9助尼克斯擊敗老鷹……
";
}
}
class Mother{
public function narrate($book){
echo "媽媽開始講故事
";
echo $book->getContent();
}
}
class Client{
public static function main(){
$mother = new Mother();
$mother->narrate(new Book());
$mother->narrate(new Newspaper());
}
}
Client::main();
既然如此隨意,還如何體現依賴倒置呢?這是因為PHP
是弱型別語言,特點就是不需要為變數指定型別,導致的結果就是隻要你的class
裡有我需要呼叫的方法(在這裡是getContent
方法),那就無論如何也不會出錯,至於你是不是實現了什麼interface
介面,都無所謂的。像這樣,是無法真正體現依賴倒置原則的。那到底如何才能真正體現依賴倒置呢?祕訣就是我們通過使用PHP的型別約束來規定narrate
函式的$book
引數必須是一個介面:
class Mother{
public function narrate(IReader $book){
echo "媽媽開始講故事
";
echo $book->getContent();
}
}
在這裡,我們規定了$book
引數必須是一個IReader
介面,那麼凡是需要讓媽媽講的讀物都必須是對於IReader
這個介面的一個實現,否則就會報錯。完整程式碼如下:
<?php
interface IReader{
public function getContent();
}
class Book implements IReader {
public function getContent(){
return "很久很久以前有一個阿拉伯的故事……
";
}
}
class Newspaper implements IReader {
public function getContent(){
return "林書豪17+9助尼克斯擊敗老鷹……
";
}
}
class Mother{
public function narrate(IReader $book){
echo "媽媽開始講故事
";
echo $book->getContent();
}
}
class Client{
public static function main(){
$mother = new Mother();
$mother->narrate(new Book());
$mother->narrate(new Newspaper());
}
}
$client = new Client();
$client->main();
你可以試著把class Newspaper
後面的implements IReader
去掉然後執行一下,馬上就會報錯:
PHP Fatal error: Uncaught TypeError: Argument 1 passed to Mother::narrate() must implement interface IReader, instance of Newspaper given, called in /Users/zhangjing/Projects/phpdesignpattern/client.php on line 29 and defined in /Users/zhangjing/Projects/phpdesignpattern/client.php:19
所以結論是:對於PHP這種弱型別語言來講,要想真正實現依賴倒置原則,必須加上型別約束,否則實現的只是表象,並不能真正體現原則的作用。