溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點(diǎn)擊 登錄注冊 即表示同意《億速云用戶服務(wù)條款》

Laravel面向接口編程的實(shí)現(xiàn)

發(fā)布時(shí)間:2021-01-25 12:26:36 來源:億速云 閱讀:252 作者:小新 欄目:編程語言

這篇文章主要介紹了Laravel面向接口編程的實(shí)現(xiàn),具有一定借鑒價(jià)值,感興趣的朋友可以參考下,希望大家閱讀完這篇文章之后大有收獲,下面讓小編帶著大家一起了解一下。

面向接口編程是編碼中的一種設(shè)計(jì)思想,這種方式基于接口而不是固定的類來構(gòu)建應(yīng)用程序。

如果您是一名程序員,那么您可能聽說過則這樣的說法,例如:面向接口編程、使用抽象類代替固定類等等。

這些都是說的同一件事,編寫應(yīng)用程序代碼時(shí),使其依賴抽象接口而不是具體的類。

為什么?

這是我第一次聽到這句話時(shí)的確切反應(yīng)。為什么要使用接口而不是類?即使創(chuàng)建了接口,我也需要創(chuàng)建一個實(shí)現(xiàn)該接口的類。這不是浪費(fèi)時(shí)間嗎?

當(dāng)然不是?。?/p>

這個世界上唯一不變的就是變化本身,也就是說,變化是永恒的。

就編程而言,這同樣沒有例外。業(yè)務(wù)需求隨著時(shí)間變化,我們的代碼也要隨之變化。

所以代碼必需保持靈活。

面向接口編程可以使代碼松散耦合且靈活。

怎么做?

觀察下面的代碼。

class Logger {
    public function log($content) 
    {
        //日志保存到文件中.
        echo "Log to file";
    }
}

這是一個將日志記錄到文件的簡單類。 我們可以在控制器中調(diào)用它。

class LogController extends Controller
{
    public function log()
    {
        $logger = new Logger;
        $logger->log('Log this');
    }
}

但如果需要將日志記錄到多個地方 (如數(shù)據(jù)庫,文件,云端等) 時(shí),我們又該怎么辦呢。

然后我們可以更改 LogController 和 Logger 類以適應(yīng)這些更改。

class Logger {
    public function logToDb($content) 
    {
        //將日志記錄到 db.
    }
    public function logToFile($content) 
    {
        //將日志保存到 file.
    }
    public function logToCloud($content) 
    {
        //將日志存儲到 cloud.
    }
}
class LogController extends Controller
{
    public function log()
    {
        $logger = new Logger;
        $target = config('log.target');
        if ($target == 'db') {
            $logger->logToDb($content);
        } elseif ($target == 'file') {
            $logger->logToFile($content);
        } else {
            $logger->logToCloud($content);
        }
    }
}

現(xiàn)在我們可以記錄不同的目標(biāo)了。但是,如果我們想將其他目標(biāo) (例如日志) 添加到 redis 服務(wù)器,該怎么辦?最后,我們將同時(shí)修改 Logger 類和 LogController 類。

如您所見,這很快就擺脫了我們的控制,并且代碼變得混亂。Logger 類很快成為一個整體。這是一場噩夢。

因此,我們需要拆分事物。遵循 SOLID 原則,我們可以將職責(zé)移至相應(yīng)的類。

class DBLogger
{
    public function log()
    {
        //將日志記錄到 db
    }
}
class FileLogger
{
    public function log()
    {
        //將日志保存到 file
    }
}
class CloudLogger
{
    public function log()
    {
        //將日志存儲到 cloud
    }
}

并且控制器更改為:

class LogController extends Controller
{
    public function log()
    {
        $target = config('log.target');
        if ($target == 'db') {
            (new DBLogger)->log($content);
        } elseif ($target == 'file') {
            (new FileLogger)->log($content);
        } else {
            (new CloudLogger)->log($content);
        }
    }
}

這樣就好多了?,F(xiàn)在如果要添加其他日志記錄目標(biāo),我們可以創(chuàng)建一個新類并將其添加到 Controller 中的 if-else。

但是,我們的控制器仍然負(fù)責(zé)選擇記錄器。對于控制器,不需要知道不同的記錄器并在它們之間進(jìn)行選擇。它只需要一個帶有 log() 方法的記錄器類來記錄內(nèi)容。

使用接口

這種情況就適合使用接口。那么什么是接口?

接口是對對象可以執(zhí)行的操作的描述。

以我們的示例為例,控制器僅需要帶有 log() 方法的記錄器類。因此,我們的接口必須描述它必須具有 log() 方法。

interface Logger
{
    public function log($content);
}

如您所見,它僅包含函數(shù)聲明,而不包含其實(shí)現(xiàn),這就是為什么將其稱為抽象的原因。

實(shí)現(xiàn)接口時(shí),實(shí)現(xiàn)接口的類必須提供接口中定義的抽象方法的實(shí)現(xiàn)細(xì)節(jié)。

在我們的示例中,任何實(shí)現(xiàn) Logger 接口的類都必須提供抽象方法 log () 的實(shí)現(xiàn)細(xì)節(jié)。

然后,我們可以在控制器中注入此接口。

class LogController extends Controller
{
    public function log(Logger $logger)
    {
        $logger->log($content);
    }
}

現(xiàn)在,控制器不再關(guān)心傳遞給它的記錄器類型。它需要知道的是它必須實(shí)現(xiàn) Logger 接口。

因此,我們需要修改 Logger 類以實(shí)現(xiàn)此接口。

class DBLogger implements Logger
{
    public function log()
    {
        //將日志記錄到 db
    }
}
class FileLogger implements Logger
{
    public function log()
    {
        //將日志存儲到 file
    }
}
class CloudLogger implements Logger
{
    public function log()
    {
        //將日志保存到 cloud
    }
}

現(xiàn)在,我們可以添加更多記錄器,而無需觸及現(xiàn)有代碼。我們要做的就是創(chuàng)建一個實(shí)現(xiàn) Logger 接口的新類。

class RedisLogger implements Logger
{
    public function log()
    {
        //將日志存儲到 redis
    }
}

我們的代碼現(xiàn)在看起來就變得靈活,低耦合了,我們可以隨時(shí)改變實(shí)現(xiàn)方式而不用去改動之前的代碼。

依賴注入

當(dāng)我們使用的是 Laravel 框架,我們可以使用服務(wù)容器去自動注冊接口的實(shí)現(xiàn)。

因?yàn)?Laravel 提供開箱即用的方法注入,所以我們只需要把接口和實(shí)現(xiàn)綁定起來。

首先我們需要創(chuàng)建一個 logger 的配置文件。 就像這樣

<?php
return [
    'default' => env('LOG_TARGET', 'file'),
    'file' => [
        'class' => App\Log\FileLogger::class,
    ],
    'db' => [
        'class' => App\Log\DBLogger::class,
    ],
    'redis' => [
        'class' => App\Log\RedisLogger::class,
    ]
];

然后在 app/Providers 路徑下 AppServiceProvider.php 的文件添加如下代碼

class AppServiceProvider extends ServiceProvider
{
    public function register()
    {
        $default = config('log.default');
        $logger = config("log.{$default}.class");
        $this->app->bind(
            App\Contracts\Logger::class, // the logger interface
            $logger
        );
    }
}

這樣做的效果是,從 logger.php 配置文件讀取默認(rèn)的 logger ,然后綁定到 Logger interface 。這樣當(dāng)我們使用 Logger interface ,容器將會幫我們解析并返回默認(rèn)的 Logger 實(shí)例。

因?yàn)槟J(rèn)的 logger 是使用 env() 助手指定的,所以我們可以在不同的環(huán)境使用不同的 logger ,例如本地環(huán)境使用 file ,生產(chǎn)環(huán)境使用 db 。

感謝你能夠認(rèn)真閱讀完這篇文章,希望小編分享的“Laravel面向接口編程的實(shí)現(xiàn)”這篇文章對大家有幫助,同時(shí)也希望大家多多支持億速云,關(guān)注億速云行業(yè)資訊頻道,更多相關(guān)知識等著你來學(xué)習(xí)!

向AI問一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI