代碼到接口鹃两,而不是實現(xiàn);程序到接口舀凛,使用抽象俊扳,而不是具體。
這些都是同一件事猛遍,在開發(fā)中馋记,我們的應(yīng)用程序應(yīng)該依賴抽象,而不是具體的類懊烤。
why?
剛開始聽梯醒,感覺不是多次一舉嗎?為什么不直接寫控制器腌紧,寫方法冤馏,寫邏輯就行了。
實際上寄啼,從架構(gòu)師的角度看,沒有什么不是變化的代箭,就是隨著時間的推移墩划,業(yè)務(wù)的變化,需求都是變化的嗡综,為了適應(yīng)變化乙帮,就不能依賴具體。
代碼到接口极景,使我們代碼松散耦合且靈活察净。
請舉例:
class Logger {
public function log($content) {
//輸出 Log 日志到文件。
echo "Log to file";
}
}
一個簡單Logger類盼樟,我們在控制器控制他
class LogController extends Controller {
public function log() {
$logger = new Logger();
$logger->log('Log this');
}
}
(簡書對代碼排版氢卡,真是支持的很不友好啊3拷伞R肭亍!)
他要記錄其他位置呢击碗?如數(shù)據(jù)庫筑悴,文件,云或其他稍途?
需要再Log類中加幾個方法
然后再控制器中寫對應(yīng)方法改進
好了阁吝,我們現(xiàn)在可以通過配置文件把日志輸出到各種終端。
但我們?nèi)绻€要再輸出日志到 redis 呢械拍?我們還需要再增加一個方法突勇,并且在控制器中再加一次判斷装盯。
控制器代碼很快就變得臃腫,如果還要輸出日志到更多地方呢与境?Logger 類中每個方法如果還需要擴展呢验夯?這對于后期維護來說并不好。
這樣做同時也不符合 SOLID 原則摔刁,我們先來拆分一下 Logger 類挥转,將職責拆分成不同的類。
再來修改LogController
看上去拆分了log,那繼續(xù)添加日志到redis,那就繼續(xù)加case吧共屈。
但依然有一個問題就是我們的控制器「知道太多了」绑谣,它應(yīng)該只去調(diào)用一個?log()?方法來記錄,而不應(yīng)該知道使用哪個 Logger 類拗引,也不應(yīng)該去實例化任何類借宵,這樣在將來有改動的時候,不論是要輸出到哪里矾削,我們都不需要再來修改?LogController?的代碼壤玫,那應(yīng)該怎么做呢?
這時候就是 interface出廠哼凯,聽下回分解欲间。
接口定義是可以執(zhí)行操作的描述
interface LogInterface{
? ? public function log($content);
}
我們一般把接口文件放在 項目目錄 App\Contracts文件里。
接口只聲明断部,不實現(xiàn)猎贴,這是他 抽象的原因。
我們實現(xiàn)接口時蝴光,必須提供實現(xiàn)接口的類的聲明方法
class? LogController? extends controller{
? ? public function Log(LogInterface $logger){
? ? ? ? $logger->log('log to');
}
}
namespace App\Logs;
use App\Contracts\LogInterface;
class DBLogger implents?LogInterface{
? ? ? ? public function log($content){
????????//輸出日志到DB
????????}
}
namespace App\Logs;
use App\Contracts\LogInterface;
class FileLogger implents LogInterface{
public function log($content){
//輸出日志到file
}
}
然后是依賴注入
在使用Laravel框架時她渴,我們可以利用它服務(wù)容器來實現(xiàn)自動注入接口實現(xiàn)
新建 config/log.php?
<?php
return [
? ? 'default' => env('Log_TARGET','file');
????'file' => [
? ? ? ? ? ? 'class' => App\Logs\FileLogger,
],
'db' => [
? ? ? ? 'class'=>App\Logs\DBLogger
]
];
并在 app\Providers\AppServiceProvider.php 添加下代碼
public function register(){
? ? ? ? $default = config('log.default');
? ? ? ? $logger = config("log.{$default}.class");
? ? ? ? $this->app->bind(
? ? ? ? ? ? \App\Contracts\LogInterface::class,
????????????$logger
????????);
}
我們從配置文件中選用日志類型,然后再config配置中綁定蔑祟,注冊服務(wù)趁耗,當我們請求接口時,容器就會解析返回實例
總結(jié):
接口允許我們創(chuàng)建松散耦合的代碼疆虚,同時提供一定程度的抽象对粪,這樣在快速切換時候,就不用現(xiàn)寫代碼装蓬。
對于大型應(yīng)用會隨著變化業(yè)務(wù)變化著拭,建議用這種,一勞永逸牍帚,不要嫌棄當時寫的代碼多儡遮,至于小型應(yīng)用,那看你心情暗赶。
真著急看鄙币,看?interface 在Laravel開發(fā)中應(yīng)用