依賴注入
當A類需要依賴於B類,也就是說需要在A類中實例化B類的對象來使用時候,如果B類中的功能發生改變,也會導致A類中使用B類的地方也要跟着修改,導致A類與B類高耦合。這個時候解決方式是,A類應該去依賴B類的接口,把具體的類的實例化交給外部。
就拿我們業務中常用的通知模塊來說。
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 |
<?php
class Message{
public function seed()
{
return 'seed email';
}
}
class Order{
protected $messager = '';
function __construct()
{
$this->messager = new Message();
}
public function seed_msg()
{
return $this->messager->seed();
}
}
$Order = new Order();
$Order->seed_msg();
|
上面的代碼是我們傳統的寫法。首先由個消息發送的類。然后在我們需要發送消息的地方,調用發送消息的接口。有一天你需要添加一個發送短信的接口以滿足不同的需求。那么你會發現你要再Message類里面做修改。同樣也要再Order類里面做修改。這樣就顯得很麻煩。這個時候就有了依賴注入的思路。下面把代碼做一個調整
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 |
<?php
interface Message{
public function seed();
}
class SeedEmail implements Message
{
public function seed()
{
return 'seed email';
}
}
class SeedSMS implements Message
{
public function seed()
{
return 'seed sms';
}
}
class Order{
protected $messager = '';
function __construct(Message $message)
{
$this->messager = $message;
}
public function seed_msg()
{
return $this->messager->seed();
}
}
$message = new SeedEmail();
$Order = new Order($message);
$Order->seed_msg();
$message = new SeedSMS();
$Order = new Order($message);
$Order->seed_msg();
|
這樣我們就實現了依賴注入的思路,是不是很方便擴展了。
服務容器
我理解的服務容器就是一個自動產生類的工廠。
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 |
<?php
interface Message{
public function seed();
}
class SeedEmail implements Message
{
public function seed()
{
return 'seed email';
}
}
class SeedSMS implements Message
{
public function seed()
{
return 'seed sms';
}
}
class Container
{
protected $binds;
protected $instances;
public function bind($abstract, $concrete)
{
if ($concrete instanceof Closure) {
$this->binds[$abstract] = $concrete;
} else {
$this->instances[$abstract] = $concrete;
}
}
public function make($abstract, $parameters = [])
{
if (isset($this->instances[$abstract])) {
return $this->instances[$abstract];
}
array_unshift($parameters, $this);
return call_user_func_array($this->binds[$abstract], $parameters);
}
}
$message = new Container();
$message->bind('SMS',function (){
return new SeedSMS();
});
$message->bind('EMAIL',function (){
return new SeedEmail();
});
$SMS = $message->make('SMS');
$SMS->seed();
|
container是一個簡單的服務容器里面有bind,make兩個方法
bind是向容器中綁定服務對象。make則是從容器中取出對象。
bind
在bind方法中需要傳入一個 concrete 我們可以傳入一個實例對象或者是一個閉包函數。
可以看到我這全使用的是閉包函數,其實也可以這樣寫
| 1 2 |
$sms = new SeedSMS();
$message->bind('SMS',$sms);
|
后面這種寫法與閉包相比的區別就是我們需要先實例化對象才能往容易中綁定服務。而閉包則是我們使用這個服務的時候才去實例化對象。可以看出閉包是有很多的優勢的。
make
make方法就從容器中出去方法。里面首先判斷了instances變量中是否有當前以及存在的服務對象,如果有直接返回。如果沒有那么會通過 call_user_func_array返回一個對象.

擁有一個明確的學習思路能更高效化的學習

點此加入該群學習