控制反轉(IOC)
想知道什麼叫控制反轉就先明白什麼叫控制不反轉(實在想不出應該怎麼叫啦,明白意思就好,不必糾結用詞雅不雅)我們舉個例子看一下,假如我們想要生產一部手機,每款手機只存在系統的差異
class Ios{
public function getSystemMark(){
echo "This is a ios Phone";
}
}
class Android{
public function getSystemMark(){
echo "This is a android Phone";
}
}
class Phone{
public function make(){
$ios = new Ios();
$ios->getSystemMark();
}
}
//產一部蘋果手機
$ios_phone = new Phone();
$ios_phone->make();
對於上面這種當實例化phone
類並且調用其中make
方法時 對象會主動的在類的內部獲取所需要的外部資源(這裏指由Ios類實例化出來的對象),這種情況就叫做控制不反轉
- 對於這種情況下有一種弊端就是當我們想要生產一部android手機時需要修改
phone
類中的make
方法這樣的話就是的代碼的耦合率更加的大。這樣的話如果想要生產多種系統的手機的話豈不是很麻煩,這個問題要怎麼解決呢??接在來就是控制反轉登場的時刻啦!看改良後的代碼 -
interface System{ public function getSystemMark(); } class Ios implements System{ public function getSystemMark(){ echo "This is a ios Phone"; } } class Android implements System{ public function getSystemMark(){ echo "This is a android Phone"; } } class Phone{ protected $system; public function __construct(System $system){ $this->system = $system; } public function make(){ $this->system->getSystemMark(); } } $ios = new Ios(); $ios_phome = new Phone($ios); $ios_phome->make(); $android = new Android(); $android_phone = new Phone($android); $android_phone->make();
- 現在我們在實例化
phone
類的時候就不用在make
的內部去實例化相應的系統類啦!這種由外部提供對象所需資源(這裏指 系統對象)的情況叫做控制反轉,實現控制反轉的方式叫做依賴注入(DI) - phone類實例化的對象調用
make
方法時,make
方法的實現依賴於 系統類所實例化得到的對象,但是這種對象不是有phone類內部實例化獲得的,而是在外部實例化夥的然後通過構造方法傳入進對象的內部的,這種方式叫做依賴注入。 -
好啦!知道了什麼叫做控制反轉、依賴注入後讓我們來看看怎麼把代碼再優化一下。上面的代碼雖然我們實現了IOC和DI,但是當我們獲取一個手機時還要自己去手動實例化 ios android的類然後再實例化phone,這麼做太不智能啦!但是我們怎麼來讓它更好一些呢!這時候我們使用IOC容器來實現就可以啦,下面代碼:
-
interface System{ public function getSystemMark(); } class Ios implements System{ public function getSystemMark(){ echo "This is a ios Phone"; } } class Android implements System{ public function getSystemMark(){ echo "This is a android Phone"; } } class Phone{ protected $system; public function __construct(System $system){ $this->system = $system; } public function make(){ $this->system->getSystemMark(); } } class Container{ private $instances; private $binds; public function binds($abstract,$concrete){ if($concrete instanceof Closure){ $this->binds[$abstract] = $concrete; }else{ $this->instances[$abstract] = $concrete; } } public function make($abstract,$params = []){ if(isset($this->instances[$abstract])){ return $this->instances[$abstract]; } if($params){ $params = [$params]; array_unshift($params, $this); return call_user_func_array($this->binds[$abstract],$params); }else{ return call_user_func($this->binds[$abstract]); } } } $container = new Container(); $container->binds("phone",function($container,$system){ return new Phone($container->make($system)); }); $container->binds("ios",function(){ return new Ios(); }); $container->binds("android",function(){ return new Android(); }); $ios_phone = $container->make("phone","ios"); $android_phone = $container->make("phone","android"); $ios_phone->make(); $android_phone->make();
ok!ioc容器的簡單實現就完成啦!更高級的IOC容器要使用類的反射來做