它是依赖注入和它是一个不好的做法?(Is it dependency injection and i

2019-08-17 11:19发布

我有一个小框架,我编写它像这样。 我不知道,如果它被称为依赖注入与否。 我不知道,如果它像一个设计模式或没有。 我也不知道,不知道,如果通过$this作为一个参数是一个不好的做法。

看一看这一点; (不工作的例子,只是写那些代码到浏览器的说明。)

/* This is engine model */
require_once('Database.class.php');
require_once('Image.class.php');
require_once('Misc.class.php');
require_once('BBCode.class.php');

class FrameWork_Engine_Model
{
    public $database, $config, $misc, $bbcode, $controller, $image;

    function __construct($config)
    {
            $this->database = new Database($configParams);
            $this->image = new Image($this);
            $this->misc = new Misc($this);
            $this->bbcode = new BBCode($this);
            $this->controller = new Controller($this); //here I call Register controller depending on routing, in this case, register controller.
    }
 ...
 }

 /* This is register controller */
 class Register extends Base_Controller
 {
       /*I can access anything over Engine Model in my controllers */
       $this->engine->database->query(); //I access database model
       $this->engine->bbcode->tag('you'); //I access bbcode model
       $this->engine->image->sanitizeUploadedFile(); //I access image model

       //etc. I can access others models like this.
 }

基本上,我的控制器可以通过发动机型号访问任何车型。 我相信, dependency injection is all about injecting dependencies into controllers? 就像,我的注册控制器需要一个数据库模式,路由模式和模板模式工作。 在这里它的一切它取决于。 是我错了?

有了这些说,我的问题是:

  1. 它是一个有效的依赖注入的例子吗? 如果不是,它是什么? 它有设计模式的名字吗?

  2. 如果没有相关的依赖注入,什么样的变化需要做是DI?

  3. 正在通过$this参数上新建的类是一种不好的做法? 如果是这样,为什么?

PS。 我知道问的话题在3个问题是不是计算器喜欢,但我不希望复制粘贴整个文本要问他们。

Answer 1:

你几乎没有。

问题1

不,我不认为这是一个有效的依赖注入的例子。 它类似于一个有点服务定位器(因为你注入整个容器到你的服务,并用它来“定位”相关的服务)。

问题2

你让依赖注入和依赖注入容器之间的小混乱。

首先,依赖注入装置推依赖关系到一个对象在运行时,而不是创建/牵引它们。

为了举例说明这一点:

//hardcoded dependecies
class BadService
{
    public function __construct() 
    {
        $this->dep1 = new ConcreteObject1();
        $this->dep2 = new ConcreteObject2();
    }
}

所以在上面的例子中, BadService使得IMPOSIBLE在运行时连接其他的依赖,因为他们已经很难拉到构造函数本身。

//service locator pattern
class AlmostGoodService
{
    public function __construct(Container $container)
    {
        $this->dep1 = $container->getADep1();
        $this->dep2 = $container->getADep2();
    }
}

AlmostGoodService例子,我们删除了前面例子中的硬相关性,但我们仍然取决于具体的实现我们的容器(意思是我们的服务是不能重复使用,而不提供针对该容器的实现)。 这是例子匹配你在做什么。

//dependecy injection    
class GoodService
{
    public function __construct($dep1, OptionalInterface $dep2)
    {
        $this->dep1 = $dep1;
        $this->dep2 = $dep2;
    }
}

GoodService服务并不关心创建它的具体的依赖关系,并与实施的“协议”的任何依赖性很容易被“连线”在运行时$dep1或为在OptionalInterface $dep2 (因此名称控制反转 - 背后依赖注入的基本概念)。

执行此布线组件被称为依赖注入容器 。

现在, 依赖注入容器 ,在它的最简单的形式,无非是能够连接最多基于某种形式的配置您在运行时对象的对象更多。

我说那你就要成功了,但也存在一些问题与您的实现:

  • 布线应该是懒惰(你不想让所有的工作在你的构造,为您的应用程序会减慢大大因为它的增长)
  • 你不应该通过整个容器( $this ,因为这样你回退到较弱)作为依赖控制反转 ,即服务定位器 。 而应该通过具体依赖于您的服务构造

问题3

有些情况下,您会发现自己想整个传递$container作为依赖的服务(即控制器或懒惰的服务工厂),但通常会更好,从这种做法远离,因为它会让你的服务更多的可重用性和易于测试。 当你觉得你的服务有太多的依赖,那么它是你的服务做过多的一个好兆头,它是分裂的好时机。

原型容器实现

因此,基于以上我的答案,这里是一个修改后的(远非完美)的实现:

/* This is the revised engine model */
class FrameWork_Engine_Model
{
    function __construct($config)
    {
            $this->config = $cofig; 
    }

    public function database()
    {
        require_once('Database.class.php');
        return new Database($this->config['configParams']);
    }

    public function bbcode()
    {
        require_once('BBCode.class.php');
        return new BBCode($this->database());
    }

    public function image()
    {
        require_once('Image.class.php');
        $this->image = new Image($this->config['extensionName']);
    }
    ....

    public function register_controller($shared = true)
    {
        if ($shared && $this->register_controller) {
          return $this->register_controller;
        }

        return $this->register_controller = new Register_Controller($this->database(), $thus->image(), $this->bbcode());
    }
 }

现在,使用您的服务:

$container = new FrameWork_Engine_Model(); 
$container->register_controller()->doSomeAction()

什么可以改善? 您应该集装箱:

  • 提供了一种共享服务 - 即初始化他们只有一次
  • 是可锁定 -提供了一种配置后,将其锁定
  • 可以“合并”与其他容器 - 这样你的应用程序将是真正的模块化
  • 允许可选依赖
  • 允许范围
  • 支持标签服务

准备使用DI容器实现

所有这些都伴随着有关清晰的文档依赖注入

  • 疙瘩 - PHP 5.3轻量级DI容器
  • Symfony2的DI容器 - PHP 5.3功能全面的DI容器
  • 果汁DI -小PHP 5.2 DI容器


Answer 2:

  1. FrameWork_Engine_Model是一个注册表( 注册模式 )。 注射注册表,依赖到所有的对象是怎样的一个误解依赖注入的。 技术上讲,它 DI,但您从一切依赖于一切 ,也带走了灵活性,DI应该提供。
  2. 如果您FrameWork_Engine_Model是为了实例化服务和管理他们的依赖,也可以将其更改为控制容器的反转 (与DI典型模式)
  3. 不,不是一般。

我不会说你的类名的选择和你的服务和控制器的责任,我不认为这是这个问题的范围之内。 只是一句话:它看起来像你的控制器做太多。 如果你有兴趣在干净的代码,你可能想看看单一职责原则 ,并保持你的控制器“瘦”,业务逻辑和数据库查询移动到服务层和输出机制,例如要设置高亮意见。

所以,回到你的例子,以及如何将其改变为依赖注入的合理使用。 一个原始的IoC容器可能看起来像:

public function createRegisterController()
{
    $controller = new RegisterController();
    $controller->setImage($this->getImageService());
    // ...
    return $controller;
}
public function getImageService()
{
    if ($this->imageService === null) {
        $this->imageService = new Image();
        // inject dependencies of Image here
    }
    return $this->imageService;
}

这里最重要的一点是: 只有注入所需的依赖关系。 不要创建一批伪装成DI全局变量。



文章来源: Is it dependency injection and is it a bad practice?