gpt4 book ai didi

c# - 原型(prototype)模式是否符合依赖注入(inject)?

转载 作者:行者123 更新时间:2023-11-30 22:03:09 24 4
gpt4 key购买 nike

在我学习依赖注入(inject)(并获得第一次实践经验)期间,我想知道我在考虑一个具体项目时遇到的一个问题,我想在不久的将来用 DI 解决这个问题。

对于不同的分析,我想动态创建注入(inject)依赖项的对象,因为我需要任意数量的对象,这可能会因用户与我的程序的交互而有所不同。我考虑过将这个需求实现为抽象原型(prototype)模式

public interface IAnalysis
{
SomeDataType DoSomething();
IAnalysis CreateObject();
}

从 IAnalysis 派生的类将负责从 CreateObject() 返回该类的新对象。依赖类可以在不知 Prop 体类型的情况下创建新对象,而只依赖于接口(interface),因此遵循了 DI 的一个主要概念。无论如何,从 IAnalysis 派生的类必须使用 new 关键字创建新对象。我读到在使用 DI 时应避免在注入(inject)器外部使用 new 创建对象,因此我不太确定这在 DI 中是否“允许”。另一方面,这对我来说似乎是一个非常明智的解决方案,因为类只创建它们自己的新对象,这实际上不应该损害 DI 原则。

我想的概念合理吗?我可以使用其他解决方案来实现这一目标吗?我实际上考虑过抽象工厂,但这会损害我对 DI 原则的理解。

最佳答案

I read that creating objects with new should be avoided outside the injector when using DI […].

这只是部分正确。我会一步一步地告诉你 new有它的位置,使用 new 可能会很好实现您的原型(prototype)模式。

让我们从显而易见的事情开始:如果我们需要一个 B 类型的实例,那么它必须由某人在某处创建。假设我们有这个:

class C
{
void Baz()
{
B b = new B(new A(…));
b.Bar();
}
}

Baz需要 B为了完成它的工作。如果我们想避免new B(…) ,我们能做的最好的就是将它从代码库中的这个特定位置删除:

class C
{
C(Func<B> newB) // instead of Func<B>, we could also inject a B directly
{ // (the difference being that we would no longer control
this.newB = newB; // when the B gets created)
}

Func<B> newB;

void Baz()
{
var b = newB();
b.Bar();
}
}

但是 B被传递给 C的构造函数仍然必须在某处创建。只是现在它在别处。

那么我们通过避免 new 获得了什么? ? C不再需要了解如何创建 B 的内部知识.

但是Func<B> newB怎么会(即工厂方法)本身创建一个 B不使用new ?看来我们不能回避new永远。

为了说明这一点,让我们继续看另一个非常相关的示例,它更接近您的问题(在 DI 上下文中实现原型(prototype)模式):抽象工厂,另一种设计模式。假设我们有一个 BFactory其唯一职责是创建类型的实例 B :

interface BFactory
{
B CreateB();
}

我们可以在不使用 new 的情况下实现吗? ?让我们以与上述相同的方式尝试:

class RedundantBFactory : BFactory
{
RedundantBFactory(Func<B> newB)
{
this.newB = newB;
}

Func<B> newB;

public B CreateB()
{
return newB();
}
}

这绝对没有意义!工厂存在的全部意义在于它封装了有关如何创建某种类型实例的知识。只是因为我们想避免使用 new在我们的工厂中,我们完全外化了这些知识,使工厂作为一个整体完全多余(因为它只是将自己的主要责任转给了另一方,后者必须做同等的工作)!

我们可以得出结论,使用 new 是合理且适当的在抽象工厂和工厂方法中(例如 BFactory 甚至上面的 newB),如果我们不希望它们完全多余:

class UsefulBFactory : BFactory
{
public UsefulAFactory(Func<A> newA)
{
this.newA = newA;
}

Func<A> newA;

public B CreateB()
{
return new B(newA());
}
}

现在您的原型(prototype)模式:原型(prototype)模式本质上是关于对象克隆的。也就是说,所有实现 IAnalysis 的类型接口(interface)必须能够创建实例的克隆(副本)。就像上面的抽象工厂示例一样,接口(interface)的唯一目的是封装某种形式的对象创建。这是它存在的首要原因,因此实现此接口(interface)的类不得将该责任委托(delegate)给外部方。同样,使用 new 是完全合理的在这种情况下:

class W : IAnalysis
{
W(X x, Y y, …)
{
this.x = x;
this.y = y;

}

public IAnalysis CreateObject()
{
return new W(x, y, …);
}
}

最后一点,只是为了强调和完善我最初的声明,即避免 new并非在所有情况下都有意义:请注意,无论如何,DI 不应该用于所有

通常,您必须决定哪些类型应该由 DI 容器处理。这些所谓的依赖项、组件或服务通常被抽象为 interface。或 abstract class BaseClass ,这样您以后就可以用一种实现替换另一种实现。唯一使用new Service(…)的地方应该在组合根中,或者(如上所示)在抽象工厂或工厂方法中(它们本身是依赖项,将在您选择的时间注入(inject)到您需要创建对象的位置)。如果你有 new Service(…)大量散布在您的代码库中,很难用一种实现替换另一种实现。

但是使用 new 是完全可以的创建原始值和值类型的实例(例如 stringTimeSpan 等)。这些类型通常不由 DI 容器实例化。

关于c# - 原型(prototype)模式是否符合依赖注入(inject)?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26250858/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com