控制反转(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容器要使用类的反射来做