0

在对依赖注入感到困惑之后,我担心会依赖 DI 容器。所以我想我把一切都和工厂联系在一起。但是似乎需要大量的工厂(每个对象一个(?))。

现在发生的情况如下:

class houseFactory
{
    protected $_di;

    public function __construct(\DI $di)
    {
        $this->_setDI($di)
    }

    protected function _setDI(\DI $di)
    {
        $this->_di = $di;
    }

    public function createObject()
    {
        return $this->_di->create('house');
    }
}

houseFactory 基本上将创建和调用代码连接在一起,而不必知道如何创建房子。但是为每个需要的对象实际调用一个新工厂真的可以吗?

现在看来是这样,因为让我们说房子不是单独通过 DI 容器那么容易解决的,而是需要某些规则。例如,它应该只有一个实例(也称为“共享”)。这些规则将进入工厂。

我的问题是:

1)这可以接受吗?

我预测会有大量的工厂,我担心这将是一个过度杀伤/巨大的缺点/违背它应该做的事情。

2) 什么时候可以使用“new”关键字?

我理解为什么移动逻辑以创建具有依赖性的新对象是一种好习惯。但它似乎是圆形的。

3)依赖注入容器在哪里以及如何在应用程序中发挥作用?

您从什么时候开始实际使用/调用 DI 容器?似乎将 DI 容器硬编码到您的应用程序中?或者这实际上是重点?

希望我的问题不会含糊不清。

提前致谢。

4

1 回答 1

0

DI 的主要目的是注入依赖项,而不是注入负责解析/创建对象的对象。在您的示例中,假设我们想使用houseFactory类来获取house类并使用它(例如 goHome 方法)。

$house = $houseFactory->createObject();
$house->goHome();

该实现不仅使您的调用者依赖于house类,而且还依赖于houseFactory类,这是一种无用的依赖。

正如 TrueWill 所说,应用程序唯一负责创建对象的地方是composition root. 这composition root是每个应用程序的起点。不幸的是,我认为纯 php 类中没有任何组合根,但是在 CI 或 Zend 等 php 框架中应该有。

为什么我们要在 中创建对象composition root

  1. 使对象创建的范围变得很小。组合根通常只包含启动应用程序的小逻辑。也许其他一些逻辑来处理一般异常,但不是其他的。因此创建对象是安全的,因为那里不存在特定的业务逻辑。
  2. 组合根不是在其他类中创建的。它被称为应用程序启动,因此在类中创建对象是安全的。

要了解有关组合根的更多信息,您可以阅读 Mark Seeman 的书或他的博客。

那么我们如何访问在组合根目录中创建的对象呢?

有些应用程序对 DI 有很好的支持,例如 ASP.Net MVC,但有些应用程序不像 ASP.Net Webform。在具有良好支持的应用程序中,您可以直接从composition root. 但是,如果没有,也许您可​​以通过静态类访问组合根 DI 容器,但只能在页面的构造函数中。因此,它最大限度地减少了对组合根的访问。

编辑1:

这是用 php 编写的没有 DI Container 的 house 类的使用示例(可能不工作,没有在 php 中使用 DI)。

class houseConsumer{
    protected $_house;

    public function __construct(\DI $house)
    {
        $this->_house($house)
    }

    public function doSomething(){
        // do something
        $this->_house->goHome();
    }
}

class compositionRoot{
    public function main(){
        $diContainer = // define the DI Container
        $houseConsumer = new houseConsumer($diContainer->create('house'));
        $houseConsumer->doSomething();
    }
}

这是 C# 控制台中的示例:

public class HouseConsumer{
    //constructor
    public HouseConsumer(IHouse house){
        this.house = house;
    }
    IHouse house;

    public void DoSomething(){
        house.GoHome();
    }
}

//this is the composition root
public class Program{ 
    public static void Main(string[] args){
        List<object> diContainer = new List<object>();
        //populate diComponent

        HouseConsumer consumer = new HouseConsumer((IHouse)diContainer[0]);
        consumer.DoSomething();
    }
}

编辑2:

DI 容器实际上是否在“主要”方法之外使用?如何在“主”方法之外创建新对象?可以说我有几个对象深。我如何在那里建造房子?

我上面的示例可以在 Asp.Net MVC 中使用,其中页面也使用 IOC 容器自动解析。不幸的是,如果你需要像 Asp.Net webforms 这样的页面中的 DI 容器,你应该使用静态,但只在构造函数中分配对象。示例(在 C# 中,我不知道如何在 php 中使用静态)。

public class Page1 : Page{
    public Page1(){
        this.house = CompositionRoot.DiContainer.Create("house");
    }

    private IHouse house;
}

这种实现仍然是安全的,因为 DIContainer 仅在页面的构造函数级别使用。但请确保不要在 Service 类中执行此操作。例子:

public class Renter : IRenter{
    public Renter(){
        this.house = CompositionRoot.DiContainer.Create("house");
    }

    private IHouse house;
}

是一个糟糕的设计。Renter 类依赖于 DIContainer。为了解决这个问题,注入IHouse类。

public class Renter : IRenter{
    public Renter(IHouse house){
        this.house = house;
    }

    private IHouse house;
}

那么Renter类的调用者应该通过house类。该示例是使用穷人的将 IRenter 类分配给 DIContainer。

Dictionary<Type, object> DiContainer = new Dictionary<Type, object>();
IHouse house = new House();
IRenter renter = new Renter(house);
DiContainer.Add(typeof(IHouse), house);
DiContainer.Add(typeof(IRenter), renter);

然后在 Page 中使用它:

public class Page1 : Page{
    public Page1(){
        this.renter = (IRenter)CompositionRoot.DiContainer[typeof(IRenter)];
    }

    private IRenter renter;
}
于 2013-05-07T06:02:31.613 回答