首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >在工厂类中利用DI

在工厂类中利用DI
EN

Stack Overflow用户
提问于 2018-03-13 18:24:03
回答 1查看 281关注 0票数 0

假设我有一组应该由工厂实例化的类。这个工厂必须向实例化的类注入一个参数。

代码语言:javascript
运行
复制
<?php
class ClassA
{
    public function __constructor(
        \My\Logger $logger,
        \Dependency\For\ClassA $dependencyA2,
        \One\More\Dependency\For\ClassA $dependencyA3,
        ...
        string $parameterInjectedByTheFactory

    ) {
        $this->logger = $logger;
        $this->dependencyA2 = $dependencyA2;
        ...
        $this->parameterInjectedByTheFactory = $parameterInjectedByTheFactory;
    }
}

代码语言:javascript
运行
复制
<?php
class ClassB
{
    public function __constructor(
        \My\Logger $logger,
        \Dependency\For\ClassB $dependencyB2,
        \One\More\Dependency\For\ClassB $dependencyB3,
        ...
        string $parameterInjectedByTheFactory
    ) {
        $this->logger = $logger;
        $this->dependencyB2 = $dependencyB2;
        ...
        $this->parameterInjectedByTheFactory = $parameterInjectedByTheFactory;
    }
}

我觉得下面的课是错的。它不应该知道ClassAClassB的特定依赖关系,不是吗?

代码语言:javascript
运行
复制
class Factory
{
    public function __constructor(
        \My\Logger $logger
    ) {
        $this->logger = $logger;
    }

    public function make($class, $myParameter)
    {
        switch($class)
        {
            case 'ClassA':
                return new $class(
                    $this->logger,
                    new \Dependency\For\ClassA,
                    ...
                    $myParameter
                )            
            case 'ClassB':
                return new $class(
                    $this->logger,
                    new \Dependency\For\ClassB,
                    ...
                    $myParameter
                )
        }
    }
}

我想利用DI自动装配来实例化classA和classB,但在工厂中注入容器是一种糟糕的做法。

一个更现实的例子。我有一个带有get($endpointCode)方法的EndpointManager,它在数组中查找$endpointCode。此数组条目包含构建端点所需的信息:

代码语言:javascript
运行
复制
<?php
[
    'endpoint1' => [
        'class' => '\My\Class\For\Dealing\With\MySQL',
        'connectionData' => 'mysql:user@localhost',
    ],

    'endpoint2' => [
        'class' => '\My\Class\For\Dealing\With\REST',
        'connectionData' => [
            'url': 'https://localhost/api/rest/',
            ...
        ],
    ],
]

EndpointManager必须实例化'class'条目中定义的类的对象,并将connectionData传递给它。但是\My\Class\For\Dealing\With\MySQL\My\Class\For\Dealing\With\REST的构造函数是异构的,每个构造函数都有自己潜在的大量依赖项。有没有办法利用DI来实例化这些对象。

对于这种情况,最好的方法是什么?

EN

回答 1

Stack Overflow用户

发布于 2018-03-13 18:34:46

您可以将具体类的创建委托给匿名函数,例如

代码语言:javascript
运行
复制
<?php

$dependencyManager>add('endpoint1', function ($di) {
     return new \My\Class\For\Dealing\With\MySQL('mysql:user@localhost', .., ...);
});

$dependencyManager>add('endpoint2', function ($di) {
     return new \My\Class\For\Dealing\With\REST('https://localhost/api/rest/', .., ..., ...);
});

要获取instance类:

代码语言:javascript
运行
复制
<?php

$endpoint1Instance = $dependencyManager->get('endpoint1');
$endpoint2Instance = $dependencyManager->get('endpoint2');

其中,add()get()方法可以像下面这样声明:

代码语言:javascript
运行
复制
<?php

class DependencyManager 
{
    private $dependencies = [];
    ...

    public function add($key, callable $factory)
    {
          $this->dependencies[$key]['instance'] = null;
          $this->dependencies[$key]['factory'] = $factory;
    }

    public function get($key)
    {
       if (isset($this->dependencies[$key]) {               
           $instance = $this->dependencies[$key]['instance'];
           if (is_null($instance)) {
               $instance = $this->dependencies[$key]['factory']($this);
               $this->dependencies[$key]['instance'] = $instance;
           }
           return  $instance;
       } else {
          throw new Exception('not found');
       }    
    }
    ...
}

您可能希望查看现有的依赖项管理器实现,例如Pimple

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

https://stackoverflow.com/questions/49253696

复制
相关文章

相似问题

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