架構(gòu) ―― 契約

2018-02-24 15:38 更新

架構(gòu) —— 契約(Contracts)

1、簡介

Laravel的契約是指框架提供的一系列定義核心服務(wù)的接口。比如,Illuminate\Contracts\Queue\Queue契約定義了隊(duì)列任務(wù)需要的方法,Illuminate\Contracts\Mail\Mailer契約定義了發(fā)送郵件所需要的方法。

每一個(gè)契約都有框架提供的相應(yīng)實(shí)現(xiàn)。比如,Laravel提供了多個(gè)驅(qū)動的隊(duì)列實(shí)現(xiàn),郵件實(shí)現(xiàn)則由?SwiftMailer驅(qū)動。

所有的Laravel契約都有其GitHub庫,這為所有有效的契約提供了快速入門指南,同時(shí)也可以作為獨(dú)立、解耦的包被包開發(fā)者使用。

1.1 契約(Contracts) VS 門面(Facades)

Laravel的門面為Laravel服務(wù)的使用提供了一個(gè)簡便的方式——不再需要從服務(wù)容器中類型提示和解析契約。然而,使用契約允許你為類定義明確的依賴,在大多數(shù)應(yīng)用中,使用門面剛剛好,但是,如果你需要更多更多松耦合,那么契約無疑是合適的,繼續(xù)看下去!

2、為什么使用契約?

關(guān)于契約你可能存有疑問。為什么要全部使用這些契約接口?難道使用契約接口不是更復(fù)雜?下面讓我們從這兩個(gè)方面來說明使用契約接口的原因:松耦合和簡單。

2.1 松耦合

首先,讓我們看看一些緩存實(shí)現(xiàn)的緊密耦合代碼:

<?php

namespace App\Orders;

class Repository{
    /**
     * 緩存
     */
    protected $cache;

    /**
     * 創(chuàng)建一個(gè)新的Repository實(shí)例
     *
     * @param  \SomePackage\Cache\Memcached  $cache
     * @return void
     */
    public function __construct(\SomePackage\Cache\Memcached $cache)
    {
        $this->cache = $cache;
    }

    /**
     * 通過ID獲取訂單
     *
     * @param  int  $id
     * @return Order
     */
    public function find($id)
    {
        if ($this->cache->has($id))    {
            //
        }
    }
}

在這個(gè)類中,代碼和給定緩存實(shí)現(xiàn)緊密耦合,因?yàn)槲覀兓谝粋€(gè)來自包的具體的緩存類,如果報(bào)的API變了,那么相應(yīng)的,我們的代碼必須做修改。

類似的,如果我們想要替換底層的緩存技術(shù)(Memcached)為別的技術(shù)實(shí)現(xiàn)(Redis),我們將再一次不得不修改我們的代碼庫。我們的代碼庫應(yīng)該并不知道誰提供的數(shù)據(jù)或者數(shù)據(jù)是怎么提供的。

我們可以基于一種簡單的、與提供者無關(guān)的接口來優(yōu)化我們的代碼,從而替代上述那種實(shí)現(xiàn):

<?php

namespace App\Orders;

use Illuminate\Contracts\Cache\Repository as Cache;

class Repository{
    /**
     * 創(chuàng)建一個(gè)新的Repository實(shí)例
     *
     * @param  Cache  $cache
     * @return void
     */
    public function __construct(Cache $cache)
    {
        $this->cache = $cache;
    }
}

現(xiàn)在代碼就不與任何特定提供者耦合,甚至與Laravel都是無關(guān)的。由于契約包不包含任何實(shí)現(xiàn)和依賴,你可以輕松的為給定契約編寫可選實(shí)現(xiàn)代碼,你可以隨意替換緩存實(shí)現(xiàn)而不用去修改任何緩存消費(fèi)代碼。

2.2 簡單

當(dāng)所有Laravel服務(wù)都統(tǒng)一在簡單接口中定義,很容易判斷給定服務(wù)提供的功能。契約可以充當(dāng)框架特性的簡明文檔。

此外,基于簡單接口,代碼也更容易理解和維護(hù)。在一個(gè)龐大而復(fù)雜的類中,與其追蹤哪些方法時(shí)有效的,不如轉(zhuǎn)向簡單、干凈的接口。

3、契約列表

下面是Laravel契約列表,以及其對應(yīng)的“門面”

契約 引用門面
Illuminate\Contracts\Auth\Guard Auth
Illuminate\Contracts\Auth\PasswordBroker Password
Illuminate\Contracts\Bus\Dispatcher Bus
Illuminate\Contracts\Broadcasting\Broadcaster
Illuminate\Contracts\Cache\Repository Cache
Illuminate\Contracts\Cache\Factory Cache::driver()
Illuminate\Contracts\Config\Repository Config
Illuminate\Contracts\Container\Container App
Illuminate\Contracts\Cookie\Factory Cookie
Illuminate\Contracts\Cookie\QueueingFactory Cookie::queue()
Illuminate\Contracts\Encryption\Encrypter Crypt
Illuminate\Contracts\Events\Dispatcher Event
Illuminate\Contracts\Filesystem\Cloud
Illuminate\Contracts\Filesystem\Factory File
Illuminate\Contracts\Filesystem\Filesystem File
Illuminate\Contracts\Foundation\Application App
Illuminate\Contracts\Hashing\Hasher Hash
Illuminate\Contracts\Logging\Log Log
Illuminate\Contracts\Mail\MailQueue Mail::queue()
Illuminate\Contracts\Mail\Mailer Mail
Illuminate\Contracts\Queue\Factory Queue::driver()
Illuminate\Contracts\Queue\Queue Queue
Illuminate\Contracts\Redis\Database Redis
Illuminate\Contracts\Routing\Registrar Route
Illuminate\Contracts\Routing\ResponseFactory Response
Illuminate\Contracts\Routing\UrlGenerator URL
Illuminate\Contracts\Support\Arrayable
Illuminate\Contracts\Support\Jsonable
Illuminate\Contracts\Support\Renderable
Illuminate\Contracts\Validation\Factory Validator::make()
Illuminate\Contracts\Validation\Validator
Illuminate\Contracts\View\Factory View::make()
Illuminate\Contracts\View\View

4、如何使用契約

那么,如果獲取一個(gè)契約的實(shí)現(xiàn)呢?相當(dāng)簡單。

Laravel中大部分類是通過服務(wù)容器進(jìn)行解析的,包括控制器、事件監(jiān)聽器、中間件、隊(duì)列任務(wù),甚至路由閉包等。因此,想要獲取一個(gè)契約的實(shí)現(xiàn),可以在被解析的類的構(gòu)造函數(shù)中類型提示該契約接口。

例如,看看事件監(jiān)聽器的代碼:

<?php

namespace App\Listeners;

use App\User;
use App\Events\NewUserRegistered;
use Illuminate\Contracts\Redis\Database;

class CacheUserInformation{
    /**
     * Redis數(shù)據(jù)庫實(shí)現(xiàn)
     */
    protected $redis;

    /**
     * 創(chuàng)建一個(gè)新的事件處理器實(shí)例
     *
     * @param  Database  $redis
     * @return void
     */
    public function __construct(Database $redis)
    {
        $this->redis = $redis;
    }

    /**
     * 處理事件
     *
     * @param  NewUserRegistered  $event
     * @return void
     */
    public function handle(NewUserRegistered $event)
    {
        //
    }
}

當(dāng)事件監(jiān)聽器被解析時(shí),服務(wù)容器會讀取類的構(gòu)造函數(shù)上的類型提示,然后注入適當(dāng)?shù)闹?。想要了解更多關(guān)于服務(wù)容器的相關(guān)內(nèi)容,可以查看其文檔。

以上內(nèi)容是否對您有幫助:
在線筆記
App下載
App下載

掃描二維碼

下載編程獅App

公眾號
微信公眾號

編程獅公眾號