Laravel4 IOC容器的好处

时间:2014-08-11 20:26:49

标签: php laravel-4 ioc-container loose-coupling

我无法理解依赖注入范围内IOC容器的好处 考虑这个基本的例子:

App::bind('Car', function()
{
    return new Car;
});

Route::get('/', function()
{
    dd(App::make('Car'));  //  resolve it
}); 

我没有看到使用IOC容器而不是在构造函数中创建新实例的好处 除了测试的好处,我读到原因是松耦合。
然而,作为汽车的“汽车”。绑定只返回一辆新车的实例,我不知道这个例子在哪种意义上会松散耦合。
对我来说,这两个似乎做了完全相同的事情。

2 个答案:

答案 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在此示例中更有用:

如果BillingNotifierInterfaceEmailBillingNotifier

实施,则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应用程序......