有人曾经告诉我,它的不同在于你如何使用它!
我曾经使用StructureMap作为DI容器来解决问题,后来重新设计为使用简单的工厂,并删除了对StructureMap的引用。
有人能告诉我它们之间的区别以及在何处使用什么,这里最好的实践是什么?
Binoj,
我认为你不必在两者之间做出选择。
将一个依赖类或接口移动到类构造函数或设置器中的行为遵循DI模式。您传递给构造函数或设置器的对象可以使用工厂实现。
何时使用?使用您开发人员熟悉的模式或模式。他们感觉最舒适并且最容易理解的是什么。
Parent
)必须实例化另一个类(Child
)的新对象,并且这些对象有复杂的协作者:@Component
class Parent {
// ...
@Autowired
Parent(Dep1 dep1, Dep2 dep2, ..., DepN depN) {
this.dep1 = dep1;
this.dep2 = dep2;
}
void method(int p) {
Child c = new Child(dep1, dep2, ..., depN, p);
// ...
}
}
Parent
只能接收 DepX
实例并将其传递给 Child
构造函数。存在的问题有:
Parent
对 Child
的了解过多Parent
拥有过多的协作者Child
添加依赖需要更改 Parent
Factory
会非常完美地适用于此:
Child
类的所有内容,就像 Parent
看到的那样Child
的知识,可以集中在 DI 配置中。Parent
类和 ChildFactory
类:@Component
class Parent {
// ...
@Autowired
Parent(ChildFactory childFactory) {
this.childFactory = childFactory;
}
void method(int p) {
Child c = childFactory.newChild(p);
// ...
}
}
@Component
class ChildFactory {
// ...
@Autowired
Parent(Dep1 dep1, Dep2 dep2, ..., DepN depN) {
this.dep1 = dep1;
this.dep2 = dep2;
// ...
this.depN = depN;
}
Child newChild(int p) {
return new Child(dep1, dep2, ..., depN, p);
}
}
工厂模式
工厂设计模式以以下特点为标志:
当你自问以下问题时,可以观察到一些事情:
这些问题通过依赖注入来解决。
依赖注入
有不同的方式来注入依赖项。简单起见,让我们选择接口注入。
在DI中,容器创建所需的实例,并将其“注入”到对象中。
因此,静态实例化被消除。
例子:
public class MyClass{
MyInterface find= null;
//Constructor- During the object instantiation
public MyClass(MyInterface myInterface ) {
find = myInterface ;
}
public void myMethod(){
find.doSomething();
}
}
DI(依赖注入)为您提供组合根,这是一个单一的集中位置,用于连接您的对象图。这往往使对象依赖关系非常明确,因为对象只请求它们需要的内容,并且只有一个地方可以获取它。
组合根是一种干净而直接的关注点分离。被注入的对象不应该依赖于 DI 机制,无论是第三方容器还是 DIY DI。DI 应该是不可见的。
工厂往往更加分散。不同的对象使用不同的工厂,而工厂代表了对象和它们实际依赖之间的另一层间接性。这个额外的层次会向对象图添加它自己的依赖关系。工厂是不可见的。工厂是中间人。
因此,更新工厂更具问题性:由于工厂是业务逻辑的依赖项,修改它们可能会产生连锁反应。组合根不是业务逻辑的依赖项,因此可以在隔离环境中进行修改。
GoF提到了更新抽象工厂的困难。他们的解释部分在这里引用here。将DI与工厂进行对比,也与问题Is ServiceLocator an anti-pattern?有很多共同之处。
最终,选择哪个可能是有主观看法的;但我认为它归结为工厂是一个中间人。问题在于,这个中间人是否通过添加除了提供产品以外的附加价值来发挥其作用。因为如果你可以在没有中间人的情况下获得同样的产品,那么为什么不削减中间人呢?
我使用两者来创建一个更易读的控制反转策略,以便开发人员在我之后需要维护它。
我使用工厂来创建不同的层对象(业务逻辑、数据访问)。
ICarBusiness carBusiness = BusinessFactory.CreateCarBusiness();
另一个开发人员将看到此内容,当创建业务层对象时,他会查看BusinessFactory和Intellisense会向开发人员提供所有可能创建的业务层。不必玩游戏,找到我想要创建的接口。
这个结构已经是控制反转了。我不再负责创建特定的对象。但是您仍然需要确保依赖注入以便轻松更改事物。创建自己的自定义依赖注入是荒谬的,所以我使用Unity。在CreateCarBusiness()中,我请求Unity解析哪个类属于此类及其生命周期。
因此,我的代码工厂依赖注入结构如下:
public static class BusinessFactory
{
public static ICarBusiness CreateCarBusiness()
{
return Container.Resolve<ICarBusiness>();
}
}