控制反转原则IOC与依赖注入DI实现方式
目录
IOC、DI ,控制反转与依赖注入已经成为现代web框架的标配专业术语。很多初学者难以理解具体含义与方法,其实都是从我们编码过程抽象归纳总结而来,大部分人都有碰到甚至自己独立处理过,只是不知道设计方式还有这么个名字。
控制反转前的代码
先看一个例子:
class A
{
protected $b;
public function method()
{
$this->b = new B();
$this->b->method();
//TODO
}
}
class B
{
public function method()
{
//TODO
}
}
//实例化A并执行A的method方法
$a = new A();
$a->method();
从上面的代码,可以看出类A依赖于类B。在没有考虑依赖注入方法前,我们大部分是这么写的代码。
如果之后要对类B类进行修改,可能会影响类A,也就是常说的耦合度高,我们想让类A和类B尽量的独立,使得耦合度低,不论是代码层面更清楚,开发过程中也适合多人协同而不互相影响,避免协同篡改他人代码。
控制反转设计原则
我们的目标就是在改动类B的情况下,尽量不影响类A。这里就涉及到了IOC控制反转设计原则。
高层模块不应该依赖于底层模块,两个都应该依赖抽象。
控制反转是一种设计原则,通过依赖注入DI方法实现这个原则。
构造器注入
初学者,通常会使用构造器注入的方式。
class A
{
public $b;
public function __construct($b)
{
$this->b=$b;
}
public function method()
{
$this->b->method();
}
}
//调用端:
$a=new A(new B());
$a->method();
构造器注入的方式比没有采用依赖注入的方式会好点,至少依赖类B的实例化不再类A中,且类B外部调整或扩展,不会影响类A。
比如我们需要扩展类B,method方法逻辑要改变,我们并不是直接修改类B,而是实现一个类B1继承类B。
class B1 extends B
{
public function method()
{
//TODO Other
}
}
//只要在调用端调整传入类A构造器的参数对象B1,不调整也不影响类A。
$a=new A(new B1());
$a->method();
也有一部分同学会使用普通方法注入的方式,比如setB()等,这些与构造器的注入大同小异。
容器注入
现在高大上的叫法叫容器注入,实际就是采用工厂模式注入,也是我们强烈推荐使用的,容器注入的方式可以达到高内聚、低耦合的理想目标。
我们实现一个容器类来管理类之间的依赖关系。当然所有类本身又依赖于容器类,所以容器类也需要注入业务类中,但容器类注入业务类,我们就采用简单的构造器或方法注入就可以了,因为只有一个依赖,且容器类简单不复杂。
<?php
class Container {
private $s = array();
//set可以简化成通过类名自动检测及自动实现类实例化或匿名函数
public function set($k, $c) {
$this->s[$k]=$c;
}
public function get($k) {
return $this->s[$k]($this); //这里始终注入容器类本身给业务类
}
}
class A
{
public $b;
public $constainer;
public function __construct(Container $constainer)
{
$this->constainer = $constainer;
}
public function method()
{
$this->b = $this->constainer->get("B");//从容器类中获取类B实例
$this->b->method();
//TODO
}
}
class B{
public $constainer;
public function __construct(Container $container){
$this->constainer = $constainer;
}
public function method(){
//同样在类B中,我们也可以通过constainer容器类来调用已经注册到容器中的相关依赖类
//TODO
}
}
$container = new Container();
$container->set("B",new B());//将类B注入容器
$container->set("B",function(){return new B();});//通过匿名函数将类B注入容器,可以保证传入时不会马上实例化,而是在真正调用时才完成实例化工作
$container->set("C",new C());//将类B注入容器
$a = new A($container);
$a->method();
本文收藏来自互联网,仅用于学习研究,著作权归原作者所有,如有侵权请联系删除
markdown 9ong@TsingChan
引用格式为收藏注解,比如本句就是注解,非作者原文。