宣告:本文並非博主原創,而是來自對《Laravel 4 From Apprentice to Artisan》閱讀的翻譯和理解,當然也不是原汁原味的翻譯,能保證90%的原汁性,另外因為是理解翻譯,肯定會有錯誤的地方,歡迎指正。
歡迎轉載,轉載請註明出處,謝謝!
依賴反轉原則
介紹
我們來到了SOLID設計原則的最終的目標遠景!它就是依賴反轉原則,它是指高階程式碼不能依賴低階程式碼。相應的,高階程式碼應該依賴一個抽象層,它是在高階程式碼和低階程式碼之間的“中間人”角色。另一方面,該原則指代抽象層不依賴具體實現,而是細節依賴抽象。如果這個讀起來很晦澀,別擔心。我們下面會對這兩個方面具體的闡述本原則。
依賴反轉原則 本原則是指高階程式碼不依賴低階程式碼,抽象不依賴具體細節。
實探
如果你已經讀過本書之前的章節,就應該對依賴反轉有一個很好的理解。我們通過下面例子來解釋:
class Authenticator {
public function __construct(DatabaseConnection $db)
{
$this->db = $db;
}
public function findUser($id)
{
return $this->db->exec(`select * from users where id = ?`, array($id));
}
public function authenticate($credentials)
{
// Authenticate the user...
}
}
可以猜到,Authenticator
類是負責查詢並驗證使用者的。我們來檢驗下類的構造器。可以看到我們有個連結資料庫的例項DatabaseConnection
。所以我們將驗證器和資料庫緊密的接合在一起了,這意味著使用者物件必須建立在關係型資料庫查詢之上。此外,我們的高階程式碼(Authenticator
類)直接依賴了低階程式碼(DatabaseConnection
類)。 首先,我們解釋下“高階”和“低階”程式碼。低階程式碼實現像這種磁碟檔案訪問,資料庫接入等。高階程式碼在低階程式碼之上實現邏輯功能的封裝,但不能將他們耦合進來。或者,高階程式碼依賴建立在低階程式碼之上的抽象層,如介面。不僅如此,低階程式碼_也_依賴於抽象層。我們來實現一個可以在Authenticator
類中使用的介面:
interface UserProviderInterface {
public function find($id);
public function findByUsername($username);
}
然後,將介面的實現注入到Authenticator
:
class Authenticator {
public function __construct(UserProviderInterface $users,
HasherInterface $hash)
{
$this->hash = $hash;
$this->users = $users;
}
public function findUser($id)
{
return $this->users->find($id);
}
public function authenticate($credentials)
{
$user = $this->users->findByUsername($credentials[`username`]);
return $this->hash->make($credentials[`password`]) == $user->password;
}
}
這些改變之後,我們的Authenticator
現在依賴兩個高階抽象:UserProviderInterface
和HasherInterface
。我們就能自由的將任何針對介面的實現注入到Authenticator
中了。比如,如果我們使用者儲存在Reids中,可以實現針對UserProvider
實現一個RedisUserProvider
類。Authenticator
現在不在直接依賴低階的儲存操作了。 此外,自從它實現介面本身後,我們的低階程式碼現在也是依賴高階的UserProviderInterface
抽象:
class RedisUserProvider implements UserProviderInterface {
public function __construct(RedisConnection $redis)
{
$this->redis = $redis;
}
public function find($id)
{
$this->redis->get(`users:`.$id);
}
public function findByUsername($username)
{
$id = $this->redis->get(`user:id:`.$username);
return $this->find($id);
}
}
反轉思想 很多開發人員在應用中使用_反轉_原則。代替這種高階直接耦合低階程式碼的“自上而下”的方式,本原則指高階、低階程式碼“同時”依賴一個高階抽象層。
在我們將Authenticator
的依賴“倒置”前,他是無法在其他資料儲存系統中使用的。在改變儲存系統的情況下,必須對Authenticator
進行修改,違背了開放封閉原則。我們已經知道,幾種原則之間是相互貫穿的。 在將Authenticator
強制實現在儲存層之上的抽象層,我們可以根據UserProviderInterface
介面約定切換成任意其他儲存系統,而無需對Authenticator
本身進行修改。傳統的依賴痛過“倒置”就能事程式碼變得非常靈活,易於改變!