首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >Laravel5.5:我在正确的模式下使用依赖注入吗?

Laravel5.5:我在正确的模式下使用依赖注入吗?
EN

Stack Overflow用户
提问于 2019-01-21 19:05:14
回答 1查看 180关注 0票数 2

我确实在app\Libs下编写了一个简单的接口。我在composer.json中注册了名称空间

代码语言:javascript
复制
"autoload": {
        "classmap": [
            "database/seeds",
            "database/factories",
            "app/Libs"
        ],

DomoticControllerInterface.php (名为" controller“,因为这是一个用于多域设置的控制器,而不是”;“)

代码语言:javascript
复制
namespace App\Libs;

interface DomoticControllerInterface
{
    /**
     * Get the current temperature.
     */
    public function getCurrentTemperature();

    /**
     * Get the current status of general heating (ON/OFF)
     */
    public function getCurrentStatusOfGeneralHeating();

}

以及实现它的类Domoticz.php

代码语言:javascript
复制
<?php
/**
 * Domoticz instance.
 *
 * @see www.domoticz.com
 */

namespace App\Libs;


class Domoticz implements DomoticControllerInterface
{

    public function getCurrentTemperature()
    {
        // TODO: Implement getCurrentTemperature() method.
        return "27.4";
    }

    public function getCurrentStatusOfGeneralHeating()
    {
        // TODO: Implement getCurrentStatusOfGeneralHeating() method.
    }
}

我写了一个HeaterService.php (模型?提供者?)在app下\Libs

代码语言:javascript
复制
<?php
/**
 * Heater Service Class.
 * This class perform work on Heater
 *
 * @since 3.0.0
 * @author sineverba
 */

namespace App\Libs;


/**
 * Class HeaterService
 * @package App\Libs
 */
class HeaterService
{

    /**
     * The domotic controller.
     *
     * @var object
     */
    private $domotic_controller;

    public function __construct($domotic_controller)
    {
        $this->setDomoticController($domotic_controller);
    }

    /**
     * Get the current temperature
     *
     * @return string the current temperature
     */
    public function getCurrentTemperature()
    {
        return $this->getDomoticController()->getCurrentTemperature();
    }

    /**
     * Set the domotic controller.
     *
     * @param object the domotic controller to use
     * @since 1.0.0
     * @author sineverba
     */
    private function setDomoticController($domoticController)
    {
        $this->domotic_controller = $domoticController;
    }

    /**
     * Get the istance of domotic controller
     *
     * @return object the domotic controller
     * @since 3.0.0
     * @author sineverba
     */
    private function getDomoticController()
    {
        return $this->domotic_controller;
    }

}

最后,在我的BaseController.php下的app\Http\控制器

代码语言:javascript
复制
<?php

/**
 * Base Controller that redirect to right controller/model,
 * based on the URL params.
 *
 * @author sineverba
 * @since 1.0.0
 */

namespace App\Http\Controllers;

use Illuminate\Http\Request;

class BaseController extends Controller
{
    //
    /**
     * Get the param from the URL and redirect to right controller.
     *
     */
    public function getTheScriptFromUrl(Request $request)
    {

        $domotic_controller = env("DOMOTIC_CONTROLLER", "Domoticz");
        if ($domotic_controller=="Domoticz") {
            $dom_controller = new \App\Libs\Domoticz();
        }
        $heater = new \App\Libs\HeaterService($dom_controller);

        echo $heater->getCurrentTemperature();
    }
}

它起作用了。我得到了27.4硬编码。

但是,这是正确的模式吗?

另一个问题是,我会在HeaterService.php构造函数中使用类型提示,但不知道如何做。

最后,我的应用程序工作(暂时),没有绑定。有可能吗?

非常感谢

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2019-01-21 19:20:47

这里有几件事不对。所以让我们一次只吃一个。

首先,如果要在app命名空间中添加类,则不需要自动加载该类。它应该已经装好了。

代码语言:javascript
复制
"autoload": {
    "psr-4": {
        "App\\": "app/"
    }
}

服务容器的一个非常强大的特性是它能够将接口绑定到给定的实现。

在OOP中,您经常会听到短语“代码到接口”,这就是这里发生的情况。

考虑到这一点,让我们创建一个HeaterServiceProvider。它的职责是将我们的依赖项注册到容器中,以便我们以后可以使用它。

代码语言:javascript
复制
<?php

namespace App\Libs;

use Illuminate\Support\ServiceProvider;

class HeaterServiceProvider extends ServiceProvider
{
    /**
    * Register bindings in the container.
    *
    * @return void
    */
    public function register()
    {
        $this->app->bind(
            'App\Libs\DomoticControllerInterface',
            'App\Libs\Domoticz
        );
    }
}

..。然后,您将在config/app.php的提供者数组中注册该服务提供者。

代码语言:javascript
复制
'providers' => [
    // 
    //
    App\Libs\HeaterServiceProvider::class
]

这将将绑定注册到应用程序的容器中。只要您需要解析App\Libs\DomoticControllerInterface,就会返回App\Libs\Domoticz的一个实例。

因此,要使用它,只需在方法中键入提示接口,如:

代码语言:javascript
复制
<?php

/**
* Base Controller that redirect to right controller/model,
* based on the URL params.
*
* @author sineverba
* @since 1.0.0
*/

namespace App\Http\Controllers;

use Illuminate\Http\Request;
use App\Libs\DomoticControllerInterface;

class BaseController extends Controller
{
    //
    /**
    * Get the param from the URL and redirect to right controller.
    *
    */
    public function getTheScriptFromUrl(DomoticControllerInterface $heater, Request $request)
    {
        // Laravel will automatically resolve an instance of 
        // App\Libs\Domoticz here, so you could just do the following
        echo $heater->getCurrentTemperature();
    }
}

在您的特殊情况下,通过在getTheScriptFromUrl()中“调整”您的实现,您实际上是在“对实现进行编码”,而不是接口。

如果您实际上不打算从容器中解决依赖关系,那么您也就违背了将东西绑定到容器的目的。

您的实现将来可能会发生变化。如果您将代码编码到一个接口,那么如果您的实现发生了更改,唯一需要做的事情就是将新的实现绑定到容器中,并且您的应用程序应该是好的。

而且,如果使用依赖项注入,那么执行测试就容易多了。您可以在测试环境中轻松地交换/模拟这些实现。

我建议您深入了解服务容器文档。您还可以查看这篇文章。作者在解释Laravel的服务容器方面做得很好。

此外,查看服务提供商的文档也会有所帮助。

编辑:基于我们在评论中的讨论,下面是如何在场景中这样做的。

代码语言:javascript
复制
<?php

namespace App\Libs;

use Illuminate\Support\ServiceProvider;

class HeaterServiceProvider extends ServiceProvider
{
    /**
    * Register bindings in the container.
    *
    * @return void
    */
    public function register()
    {
        $implementation = 'Homeassistant'; // You could be pulling this from anywhere
        $this->app->bind(
            'App\Libs\DomoticControllerInterface',
            "App\Libs\{$implementation}"
        );
    }
} 

关键是,实际上不需要在任何地方创建实现的实例,因为您已经将其绑定到控制器中。

就我们的具体情况而言,如下:

代码语言:javascript
复制
<?php

/**
* Base Controller that redirect to right controller/model,
* based on the URL params.
*
* @author sineverba
* @since 1.0.0
*/

namespace App\Http\Controllers;

use Illuminate\Http\Request;
use App\Libs\DomoticControllerInterface;

class BaseController extends Controller
{
    //
    /**
    * Get the param from the URL and redirect to right controller.
    *
    */
    public function getTheScriptFromUrl(DomoticControllerInterface $heater, Request $request)
    {
        // Laravel will automatically resolve an instance of 
        // App\Libs\Homeassistant here, so you could just do the following
        echo $heater->getCurrentTemperature();
    }
}

我希望这是有意义的:)

票数 4
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/54296357

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档