契約
簡介
laravel 的契約是對應(yīng)用框架的核心服務(wù)所要求的一種強有力的約束请琳。它本身定義一些接口座云,要求服務(wù)必須要遵守骗污。比如,Illuminate\Contracts\Queue\Queue
契約定義了隊列任務(wù)所必須的方法点骑,而 Illuminate\Contracts\Mail\Mailer
契約定義了一些發(fā)送郵件所必須的方法。
每種契約在框架中都有相應(yīng)的提供者去進(jìn)行實現(xiàn)谍夭。比如黑滴,laravel 提供了多種驅(qū)動的隊列任務(wù)的實現(xiàn),還有其中一個的郵件服務(wù)的實現(xiàn)是由 SwiftMailer 集成的紧索。
所有的 laravel 契約你都可以在這里找到:GitHub袁辈。這里提供了一個對 laravel 契約參考的快速入口,你可以很好的對這些單一解耦的包進(jìn)行獨立實現(xiàn)的開發(fā)齐板。
契約 Vs. 假面(Facades)
laravel 的假面模式提供了一種簡單的方法去從服務(wù)容器中取出服務(wù)而不需要使用類型提示吵瞻。使用契約可以使你明確的定義類間的依賴。而對于大多數(shù)應(yīng)用來說甘磨,使用假面模式就可以了橡羞。但是,如果你想要松耦合易擴(kuò)展的服務(wù)济舆,那么契約可以實現(xiàn)卿泽。
為什么使用契約?
對于契約,你可能會產(chǎn)生很多的疑問签夭。為什么要總是使用接口齐邦?使用接口不是會變的更復(fù)雜嗎?讓我們來提煉一下使用接口的原因:松耦合和簡潔性第租。
松耦合
首先措拇,讓我們來看一下一個緊耦合的關(guān)于緩存的實現(xiàn),請閱讀下面的代碼好好思考一下:
<?php
namespace App\Orders;
class Repository
{
/**
* The cache instance.
*/
protected $cache;
/**
* Create a new repository instance.
*
* @param \SomePackage\Cache\Memcached $cache
* @return void
*/
public function __construct(\SomePackage\Cache\Memcatched $cache)
{
$this->cache = $cache;
}
/**
* Retrieve an Order by ID.
*
* @param int $id
* @return Order
*/
public function find($id)
{
if ($this->cache->has($id)) {
//
}
}
}
在上面的類中慎宾,代碼給予了類一個緊耦合的緩存的實現(xiàn)丐吓。之所以說是緊耦合的,是因為它依賴于一個具體的實現(xiàn)類趟据,也就是說它和這個包的供應(yīng)商是緊密耦合的券犁。如果我們需要換一個包的供應(yīng)商,那么我們就要修改我們的代碼汹碱。
同樣的粘衬,如果我們想要切換我們的底層緩存驅(qū)動,從 memcached 切換到 redis咳促,那么我們也必須要修改大量的業(yè)務(wù)代碼稚新。所以,鑒于此跪腹,我們的資料庫不應(yīng)該對所提供的依賴需要知道的太多枷莉,而僅僅需要知道他們提供了我們所需的就可以了(這和鴨子類型的故事有點相似)。
鑒于此尺迂,我們可以采取一種與上述相反的方法來進(jìn)行解耦笤妙。我們提供一個無關(guān)具體實現(xiàn)的接口:
<?php
namespace App\Orders;
use Illuminate\Contracts\Cache\Repository as Cache;
class Respository
{
/**
* The cache instance.
*/
protected $cache;
/**
* Create a new repository instance.
*
* @param Cache $cache
* @return void
*/
public function __construct(Cache $cache)
{
$this->cache = $cache;
}
}
現(xiàn)在上面的代碼并沒有連接到任何的具體實現(xiàn)庫,甚至是 laravel噪裕。因為契約只定義了接口蹲盘,它并不包含任何的依賴和實現(xiàn),所以你可以非常簡單的去實現(xiàn)任何給定的契約膳音,你只需要根據(jù)契約編寫一個不同的實現(xiàn)就可以進(jìn)行輕松的替換召衔。而并不用修改之前寫過的代碼。
簡單
當(dāng)所有的 laravel 的服務(wù)都通過簡單整潔的接口進(jìn)行定義祭陷,那么它就可以被非常輕松的確定所給定服務(wù)具有哪些功能苍凛。這樣也可以說 laravel 的契約服務(wù)其實是已經(jīng)提供了簡潔的功能文檔了。
契約參考
下面是 laravel 契約及其對應(yīng)的假面的參考:
怎么使用契約
那么兵志,如何得到一個契約的實現(xiàn)呢醇蝴?其實這相當(dāng)?shù)暮唵巍?/p>
在 laravel 中很多類型的類都是通過服務(wù)容器來獲取的,包括控制器想罕,事件監(jiān)聽器悠栓,中間件,隊列任務(wù),和路由閉包惭适。所以笙瑟,你可以直接通過在構(gòu)造函數(shù)中使用類型提示來構(gòu)造接口依賴,這樣在類被解析時會自動的獲取契約的實例癞志,我們通過一個簡單的例子來看一下:
<?php
namespace App\Listeners;
use App\User;
use App\Events\NewUserRegistered;
use Illuminate\Contracts\Redis\Database;
class CacheUserInformation
{
/**
* The Redis database implementation.
*/
protected $redis;
/**
* Create a new event handler instance.
*
* @param Database $redis
@ @return void
*/
public function __construct(Database $redis)
{
$this->redis = $redis;
}
/**
* Handle the event.
*
* @param NewUserRegistered $event
* @return void
*/
public function handle(NewUserRegistered $event)
{
//
}
}
一旦事件監(jiān)聽器被解析往枷,服務(wù)容器就會讀構(gòu)造函數(shù)中的類型提示,然后根據(jù)類型提示去注入適當(dāng)?shù)膶嵗啾jP(guān)于更多的在服務(wù)容器中進(jìn)行類的綁定注冊师溅,你可以查看服務(wù)容器的文檔。