对于 sealed 类,是否有比抽象工厂更简单的替代方案?
Is there an easier alternative to Abstract Factory for sealed classes?
根据this问题,在使用ioc-container时使用运行时参数初始化新对象的方法是创建抽象工厂。
在我的示例中,我有这个 class:
internal sealed class AssetsDownloadingProcess
{
private readonly IBackgroundWorker _backgroundWorker;
private readonly IAssetsStorage _assetsStorage;
private readonly Parameters _parameters;
public AssetsDownloadingProcess(IBackgroundWorker backgroundWorker,
IAssetsStorage assetsStorage, Parameters parameters)
{
_parameters = parameters.Clone();
_backgroundWorker = backgroundWorker;
_assetsStorage = assetsStorage;
}
}
以及建造它的工厂:
internal sealed class AssetsDownloadingProcessFactory
{
private readonly IBackgroundWorker _backgroundWorker;
private readonly IAssetsStorage _assetsStorage;
public AssetsDownloadingProcessFactory(IBackgroundWorker backgroundWorker,
IAssetsStorage assetsStorage)
{
_backgroundWorker = backgroundWorker;
_assetsStorage = assetsStorage;
}
public AssetsDownloadingProcess CreateProcess(
AssetsDownloadingProcess.Parameters parameters)
{
return new AssetsDownloadingProcess(
_backgroundWorker, _assetsStorage, parameters);
}
}
如您所见,AssetsDownloadingProcess
没有实现任何接口,也永远不会被另一个 class 取代。因此这个工厂只不过是一段无用的代码。它可以完全省略以支持 AssetsDownloadingProcessFactory
构造函数。但是,我不能对构造函数使用依赖注入。
我想从我的 IoC 容器中使用注入的好处,而无需创建工厂和创建无用代码的麻烦。这样做的正确方法是什么?我是不是遗漏了什么或者使用了错误的 DI?
一般来说,您应该避免使用运行时数据来创建和初始化您的应用程序组件,如 here 所述。通过构造函数传入运行时数据这一事实迫使您创建一个工厂。
the article针对将运行时数据注入组件的问题给出的解决方案是让运行时数据通过以下任一方法调用初始化对象图:
- 通过 API 或
的方法调用传递运行时数据
- 从允许解析运行时数据的特定抽象中检索运行时数据。
如果在构建对象图期间不使用运行时数据,则可以使用 Composition Root 中的 DI 创建组件,因此您的问题就会消失。
然而这样做并不总是可行,如果不可行,抽象工厂就是解决方案。
然而,由于对象组合应该仅发生在应用程序的 Composition Root 中,这意味着您的抽象工厂 必须是 抽象。只有这样才能防止 AssetsDownloadingProcess
组件的构造发生在组合根内。
方法是:
- 定义一个抽象,即
IAssetsDownloadingProcessFactory
在这个工厂的消费者所在的应用层。
- 在复合根内部创建此抽象的实现。
不使用抽象意味着消费者将依赖于具体的 AssetsDownloadingProcessFactory
class(即 Dependency Inversion Principle violation)并将对象组合从组合根中拉出.这将导致对象组合分散在整个应用程序中,从而阻碍可维护性。
根据this问题,在使用ioc-container时使用运行时参数初始化新对象的方法是创建抽象工厂。
在我的示例中,我有这个 class:
internal sealed class AssetsDownloadingProcess
{
private readonly IBackgroundWorker _backgroundWorker;
private readonly IAssetsStorage _assetsStorage;
private readonly Parameters _parameters;
public AssetsDownloadingProcess(IBackgroundWorker backgroundWorker,
IAssetsStorage assetsStorage, Parameters parameters)
{
_parameters = parameters.Clone();
_backgroundWorker = backgroundWorker;
_assetsStorage = assetsStorage;
}
}
以及建造它的工厂:
internal sealed class AssetsDownloadingProcessFactory
{
private readonly IBackgroundWorker _backgroundWorker;
private readonly IAssetsStorage _assetsStorage;
public AssetsDownloadingProcessFactory(IBackgroundWorker backgroundWorker,
IAssetsStorage assetsStorage)
{
_backgroundWorker = backgroundWorker;
_assetsStorage = assetsStorage;
}
public AssetsDownloadingProcess CreateProcess(
AssetsDownloadingProcess.Parameters parameters)
{
return new AssetsDownloadingProcess(
_backgroundWorker, _assetsStorage, parameters);
}
}
如您所见,AssetsDownloadingProcess
没有实现任何接口,也永远不会被另一个 class 取代。因此这个工厂只不过是一段无用的代码。它可以完全省略以支持 AssetsDownloadingProcessFactory
构造函数。但是,我不能对构造函数使用依赖注入。
我想从我的 IoC 容器中使用注入的好处,而无需创建工厂和创建无用代码的麻烦。这样做的正确方法是什么?我是不是遗漏了什么或者使用了错误的 DI?
一般来说,您应该避免使用运行时数据来创建和初始化您的应用程序组件,如 here 所述。通过构造函数传入运行时数据这一事实迫使您创建一个工厂。
the article针对将运行时数据注入组件的问题给出的解决方案是让运行时数据通过以下任一方法调用初始化对象图:
- 通过 API 或 的方法调用传递运行时数据
- 从允许解析运行时数据的特定抽象中检索运行时数据。
如果在构建对象图期间不使用运行时数据,则可以使用 Composition Root 中的 DI 创建组件,因此您的问题就会消失。
然而这样做并不总是可行,如果不可行,抽象工厂就是解决方案。
然而,由于对象组合应该仅发生在应用程序的 Composition Root 中,这意味着您的抽象工厂 必须是 抽象。只有这样才能防止 AssetsDownloadingProcess
组件的构造发生在组合根内。
方法是:
- 定义一个抽象,即
IAssetsDownloadingProcessFactory
在这个工厂的消费者所在的应用层。 - 在复合根内部创建此抽象的实现。
不使用抽象意味着消费者将依赖于具体的 AssetsDownloadingProcessFactory
class(即 Dependency Inversion Principle violation)并将对象组合从组合根中拉出.这将导致对象组合分散在整个应用程序中,从而阻碍可维护性。