簡單分析如下程式碼,是否存在問題?
class UserController extends BaseController{
public function getIndex() {
$users = User::all();
return View::make('users.index', compact('users'));
}
}
分析:
這段程式碼很 簡短,但我們要想測試這段程式碼的話就一定會和實際的資料庫發生聯絡。
也就是說, Eloquent ORM(譯者注:Laravel的資料庫物件模型庫)和該控制器有著緊耦合。如果不使用Eloquent ORM,不連線到實際資料庫,我們就沒辦法執行或者測試這段程式碼。這段程式碼同時也違背了“關注分離”這個軟體設計原則。
簡單講:這個控制器知道的太多了。 控制器不需要去了解資料是從哪兒來的,只要知道如何訪問就行。控制器也不需要知道這資料是從MySQL或哪兒來的,只需要知道這資料目前是可用的。
每一個類都應該有單獨的職責,並且該職責應完全被這個類封裝。
//定義介面
interface UserRepositoryInterface
{
public function all();
}
//實現介面
class DbUserRepository implements UserRepositoryInterface
{
public function all()
{
return User::all()->toArray();
}
}
// 面向介面程式設計,透過建構函式,注入例項(實現介面的任意類例項)
class UserController extends BaseController
{
public function __construct(UserRepositoryInterface $users)
{
$this->users = $users;
}
public function getIndex()
{
$users=$this->users->all();
return View::make('users.index', compact('users'));
}
}
分析:
現在我們的控制器就完全和資料層面無關了。在這裡無知是福!
我們的資料可能來自MySQL,MongoDB或者Redis。我們的控制器不知道也不需要知道他們的區別。
僅僅做出了這麼小小的改變,我們就可以獨立於資料層來測試Web層了,將來切換儲存實現也會很容易。
記得要保持清晰的責任邊界。 控制器和路由是作為HTTP和你的應用程式之間的中介軟體來用的。當編寫大型應用程式時,不要將你的領域邏輯混雜在其中(控制器、路由)。
場景:提醒使用者交錢,需用到支付 和 通知 兩個方法。
//定義賬單支付介面
interface BillerInterface {
public function bill(array $user, $amount);
}
//定義賬單通知介面
interface BillingNotifierInterface {
public function notify(array $user, $amount);
}
//實現賬單支付介面,同時注入,賬單通知介面
class StripeBiller implements BillerInterface{
public function __construct(BillingNotifierInterface $notifier)
{
$this->notifier = $notifier;
}
public function bill(array $user, $amount)
{
$this->notifier->notify($user, $amount);
}
}
//使用sms作為賬單支付通知,那我們如何做依賴注入呢?很簡單:
$biller = new StripeBiller(new SmsNotifier);
分析:
這就是依賴注入。(與容器ioc可以是脫離獨立存在的,後面會講解ioc)
biller不需再考慮提醒使用者的事兒,我們直接傳給他一個提示器(notifier)。 這種微小的改動能使你的應用煥然一新。
你的程式碼馬上就變得更容易維護, 因為明確指定了類的職責邊界。 並且更容易測試, 你只需使用模擬依賴即可。
依賴注入的核心,是基於介面程式設計,實際目的在於解耦,使得類之間更加獨立,健壯,易於維護。
本作品採用《CC 協議》,轉載必須註明作者和本文連結