依赖注入与抽象工厂——选择正确的模式

Dependency Injection vs Abstract Factory - choosing the right pattern

我正在开发将问题从旧问题跟踪系统迁移到新问题跟踪系统的工具。我已经用界面将所有东西分开,但我不确定将它们粘合在一起的最佳方法是什么。我有 3 个依赖项,需要运行时数据:

这 3 个依赖项是许多其他依赖项的依赖项。除了将这 3 个注册为单例(通过 DI 容器)之外,我想不出其他方法来粘合所有内容。我也知道,单例被认为是一种不好的模式,所以我正在考虑切换到抽象工厂。

迫使我使用单例的示例关系:

INewSystemClient 需要用户、密码、主机等运行时数据

我应该切换到抽象工厂并让工厂创建对象而不是 DI 容器吗?

我认为您混淆了术语,就像 Singleton pattern (most say it's an anti-pattern now) is not the same as a singleton instance in your IOC, an Abstract factory pattern is not the same as a DI factory. What you need to think about is scopes 或创建和处置对象时一样。

在您的桌面应用程序中,可以有多个范围,您可以在其中注册一个对象(在应用程序级别或 "a singleton"、模块级别、线程级别、页面级别... ) 这通常取决于您使用的框架(Prism、MvvmLight、caliburn.micro...)如果您正在构建自己的系统,您可能想看看其他一些框架是如何做到的。 我知道 Unity 有一种很酷的方式来处理 factories and lazy 初始化。

通常,单例实例最适合用于不会在多个线程中访问的内容,这些线程会更改某些值。这是你需要创建锁的时候,你可以像阻塞你的 UI 线程那样大幅度地减慢速度。例如,如果你有一个 HttpClient 只调用一个后端 api,每个人都可以使用它,那么让它成为一个单一的范围是有意义的。

例如,如果您想写入数据库,您可能希望每个页面都有不同的 EF 上下文,这样实体跟踪就不会在两个页面上发生。

I have 3 dependencies, that require runtime data:

从你的问题来看,不清楚这些依赖项如何使用运行时数据。如果他们在初始化期间需要它,那就是 a code smell。如果您通过对已初始化(且不可变)classes 的方法调用传递运行时数据,那完全没问题。

I also know, that singletons are considered a bad pattern, so I'm considering switching to abstract factory.

Filip Cordas 已经谈到了这一点,但我想重复一遍:你混淆了两件事。在应用 DI 时,单例模式 是一件坏事,但在运行时有一些 class 的单个实例(a.k.a。单身生活) 完全没问题。有些人(比如我)更喜欢让 all 组件注册到 Singleton Lifestyle,因为这会强制实现不变性和无状态性,从而简化注册并防止所有各种常见的错误配置,例如 Captive Dependencies.

Should I switch to abstract factory and make factory create objects instead of DI container?

here 所述,抽象工厂通常不是正确的解决方案,我认为它们是一种代码味道。它们通常用于使用运行时数据构建应用程序组件,但如前所述,应用程序组件在构建期间不应需要运行时数据。