通过laravel了解DI/IoC

高级模块不应该依赖于低级模块,两者都应该依赖于抽象对象。
抽象不应该依赖于细节,细节应该取决于抽象。
—Robert C. Martin

「ioc 依赖注入」的结果就是「DI 控制反转」的目的,也就说 控制反转 的最终目标是为了 实现项目的高内聚低耦合,而 实现这种目标 的方式则是通过 依赖注入。

说白了 DI/ioc 其实是抽象工厂模式的一种升华(超级工厂)。

一、依赖的产生

直接上代码:

interface interfaceB{}
class B implements interfaceB
{
	public function someFun(){
		echo "DI/IoC";
	}
}

class A
{
	protected $a; //放入B的实例
	public function __construct(interfaceB $objectB){ //类型提示类(面向接口)
		$this->a = $objectB;
	}
	public function aFun(){
		$this->a->someFun();//调用B类的方法
	}
}

$bb = new B();
$a = new A($bb);
$a->aFun();

二、IoC容器

上面的例子我们是通过手动的方式注入依赖,而IoC可以自动实现依赖注入。下面通过laravel框架中的设计方法进行简化。

class Container
{
	protected $bindings = [];

	//2.1绑定*************************
	public function bind($abstract, $concrete=null, $shared = false){

		//如果不是回调函数,则产生一个回调函数
		if(! $concrete instanceof Closure){
			$concrete = $this->getClosure($abstract,$concrete);
		}
		$this->bindings[$abstract] = compact('concrete','share');
	}

	//默认生成的回调函数
	protected function getClosure($abstract, $concrete){
		return function($c) use($abstract, $concrete){
			$method = ($abstract == $concrete)?'build':'make';
			return $c->$method($concrete);
		};
	}
	//*************************************
	//2.2解析-解决依赖
	public function make($abstract){
		$concrete = isset($this->bindings[$abstract])? $this->bindings[$abstract]['concrete'] : $abstract;

		if($this->isBuildable($concrete,$abstract)){
			$object = $this->build($concrete);
		}else{
			$object = $this->make($concrete);
		}
		return $object;
	}

	protected function isBuildable($concrete, $abstract){
		return $concrete === $abstract || $concrete instanceof Closure;
	}
	//2.3实例*****************************************
	public function build($concrete){
		if ($concrete instanceof Closure) {
			return $concrete($this);
		}

		$reflector = new ReflectionClass($concrete);

		if (! $reflector->isInstantiable()) {
			echo $message = "Target [$concrete] is not instantiable.";
		}

		$constructor = $reflector->getConstructor();//获取类的构造函数
		if (is_null($constructor)) {
			return new $concrete;
		}

		$dependencies = $constructor->getParameters();//构造函数中的参数
		$instances = $this->getDependencies($dependencies);

		return $reflector->newInstanceArgs($instances);
	}

	//解决构造函数参数中存在依赖,则继续解析依赖
	protected function getDependencies($parameters)
	{
		$dependencies = [];

		foreach ($parameters as $parameter) {
			$dependency = $parameter->getClass();

			if(is_null($dependency)) {
				$dependencies[] = null;
			}else{
				$dependencies[] = $this->resolveClass($parameter);
			}
		}

		return $dependencies;
	}
	protected function resolveClass(ReflectionParameter $parameter)
	{
		return $this->make($parameter->getClass()->name);//获得类型提示类
	}
	//************************************************************
}

$app = new Container();
$app->bind('interfaceB','B');
$app->bind('aTestObj','A');

$aTestObj = $app->make('aTestObj');
$aTestObj->aFun();

三、超级工厂

工厂模式以及抽象工厂模式大家应该都有了解,为什么说ioc是超级工厂呢。假如上面的例子拓展一下。实例A这时不要依赖B类了,要用C类。

_实际的场景如(用烂了的例子),工厂生产汽车。之前用的是德国牌子的TUV轮毂,现在要用日本牌子的轮毂。当然同样都是轮子,因为材料、重量 甚至尺寸以及功能有出入。如果在原用的基础上改甚是麻烦,这时只需重新再写一个类C,而不动A类 _

class C implements interfaceB
{
    protected $c = '日本';
	public function someFun(){
		echo $this->c;
	}
}

//修改绑定关系
$app = new Container();
$app->bind('interfaceB','C');//达到DI控制反转目的
$app->bind('aTestObj','A');

$aTestObj = $app->make('aTestObj');
$aTestObj->aFun();

四、容器

对服务容器进行一个理解:

容器就是一个装东西的,好比碗。而服务就是这个碗要装的饭呀,菜呀,等等东西。当我们需要饭时,我们就能从这个碗里拿到。如果你想在饭里加点菜(也就是饭依赖注入了菜),我们从碗里直接拿饭就可以了,而这些依赖都由容器解决了(这也就是控制反转)。

我们需要做的就是对提供的服务进行维护。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值