我无法理解依赖注入范围内IOC容器的好处 考虑这个基本的例子:
App::bind('Car', function()
{
return new Car;
});
Route::get('/', function()
{
dd(App::make('Car')); // resolve it
});
我没有看到使用IOC容器而不是在构造函数中创建新实例的好处
除了测试的好处,我读到原因是松耦合。
然而,作为汽车的“汽车”。绑定只返回一辆新车的实例,我不知道这个例子在哪种意义上会松散耦合。
对我来说,这两个似乎做了完全相同的事情。
答案 0 :(得分:5)
你是对的,在人为的例子中,通常有点难以确切地看到你获得了什么好处。考虑一个更贴近现实世界的示例控制器:
class TestController
{
public function __construct(CarRepositoryInterface $car)
{
$this->_repository = $car;
}
public function route($id)
{
return View::make('my.view')->with('car', $this->_repository->find($id));
}
}
非常简单,一个存储库被注入到控制器的构造函数中,然后在路由中使用它来通过id加载特定的汽车。存储库的详细信息并不重要,并且可能是服务提供商将CarRepositoryInterface
绑定到具体的CarRepository
实现:
class RepositoryServiceProvider extends ServiceProvider
{
public function register()
{
$this->app->bind('CarRepositoryInterface', function($app) {
return new EloquentCarRepository(new Car());
});
}
}
所以,每次构造控制器时,都会创建一个EloquentCarRepository
并将其注入到构造函数中供控制器使用。
但是等等,如果你想从使用Eloquent切换到Doctrine,会发生什么?由于我们在这里利用依赖注入,因此您不必更改控制器中的单行代码(或可能正在使用您当前实现的任何其他控制器)。您所要做的就是定义CarRepositoryInterface
的其他实现,比如DoctrineCarRepository
,并更改服务提供商中的一行代码:
return new DoctrineCarRepository();
依赖于CarRepositoryInterface
的其他所有内容现在神奇地有效。所有这一切都要归功于IoC。
您还可以向服务提供商添加更复杂的逻辑:
public function register()
{
$this->app->bind('CarRepositoryInterface', function($app) {
if($app->environment() == 'production') {
return new EloquentCarRepository(new Car());
} else {
return new DoctrineCarRepository(new Car());
}
});
}
此处EloquentCarRepository
仅在生产环境中使用,而在任何其他环境中,DoctrineCarRepository
将被使用。 (这个例子只是为了说明如何在运行时更多地控制对象的构造类型,而不是我提倡实际执行此操作。)
<强>附录强>
正如我在评论中所述,这是一种用法类型,您不确定在运行之前您将需要什么类型的对象。还有另一种用法:Depedency Management。
假设您有一个依赖于另一个对象的对象:
class MyObject
{
public function __construct(AnotherObject $obj)
{
$this->obj = $obj;
}
}
假设AnotherObject
依赖于另一个对象:
class AnotherObject
{
public function __construct(YetAnotherObject $obj)
{
$this->obj = $obj;
}
}
这可能会很快失控,您可以在实际创建对象之前结束需要满足的长链依赖关系。使用IoC,您只需从容器中取出一个实例:
$myObject = app()->make('MyObject');
只要IoC可以构建所有依赖项,您就不必执行以下操作:
$yetAnotherObj = new YetAnotherObject();
$anotherObj = new AnotherObject($yetAnotherObj);
$myObject = new MyObject($anotherObj);
答案 1 :(得分:3)
您发布的示例,并不代表IoC容器的真实用例...
IoC Container在此示例中更有用:
如果BillingNotifierInterface
由EmailBillingNotifier
App::bind('BillingNotifierInterface', function()
{
return new EmailBillingNotifier;
});
BillerInterface
正在使用由StripeBiller
实现的App::bind('BillerInterface', function()
{
return new StripeBiller(App::make('BillingNotifierInterface'));
})
,如下所示:
EmailBillingNotifier
但是,您的团队突然想要从SMSBillingNotifier
更改为App::bind('BillingNotifierInterface', function()
{
return new SMSBillingNotifier;
});
,您只需更改1行,您的应用就会像猫一样顺利工作......
{{1}}
这是一个真正的IoC CONTAINER应用程序......