向类注入工厂以动态创建资源是否为依赖注入最佳实践?
问题解答
1. 注入工厂是否为合理的最佳实践?
你的这种注入工厂接口的做法完全合理,甚至在需要动态创建数量不确定的对象(比如你这里通过XML配置的N个Requester)的场景下,是非常推荐的实践。
核心原因:
- 遵循控制反转(IoC)原则:
Application没有直接创建Requester,而是通过注入的工厂接口获取实例,把对象创建的控制权交给外部。 - 符合依赖倒置原则:只要给
RequesterFactory定义对应的IRequesterFactory接口,Application依赖的就是抽象而非具体实现,你可以轻松替换工厂——比如测试时用返回模拟Requester的工厂,不用依赖真实XML配置,大幅降低测试成本。 - 完美适配动态场景:DI容器启动时没法预先注册所有
Requester(数量由运行时配置决定),通过工厂延迟创建实例,刚好解决了这个核心问题。
唯一要补的细节:给RequesterFactory定义IRequesterFactory接口,确保依赖抽象而非具体类。
2. 如何通过依赖注入创建XML配置的N个对象?
结合你的场景,具体步骤如下:
第一步:完善接口定义
先给工厂定义抽象接口,保证依赖倒置:
public interface IRequesterFactory { List<Requester> CreateRequesters(); } // 让具体工厂实现接口 public class RequesterFactory : IRequesterFactory { // 你的现有代码... }
第二步:在工厂中解析配置并创建实例
在CreateRequesters方法里,通过注入的IConfigurationManager读取XML配置,解析每个服务器的信息(地址、请求文件列表等),再逐个创建Requester实例。
如果Requester本身有依赖(比如ILogger、HttpClient),不要直接new,可以通过DI容器的服务提供者来创建带依赖的实例,工厂里使用服务定位器是可接受的场景:
public class RequesterFactory : IRequesterFactory { private readonly IConfigurationManager _configurationManager; private readonly IServiceProvider _serviceProvider; // 注入服务提供者,用来创建带依赖的Requester public RequesterFactory(IConfigurationManager configurationManager, IServiceProvider serviceProvider) { _configurationManager = configurationManager; _serviceProvider = serviceProvider; } public List<Requester> CreateRequesters() { var requesters = new List<Requester>(); // 从XML读取所有服务器配置 var serverConfigs = _configurationManager.GetServerConfigurations(); foreach (var config in serverConfigs) { // 用ActivatorUtilities创建带依赖+配置参数的Requester实例 var requester = ActivatorUtilities.CreateInstance<Requester>( _serviceProvider, config.ServerUrl, config.RequestFiles ); requesters.Add(requester); } return requesters; } }
第三步:注册DI服务
把相关服务注册到DI容器(以ASP.NET Core为例):
services.AddSingleton<IConfigurationManager, XmlConfigurationManager>(); services.AddSingleton<IRequesterFactory, RequesterFactory>(); services.AddTransient<Requester>(); // 每个Requester对应不同配置,用Transient生命周期
第四步:修正Application代码错误
你的代码里有两处小问题,修正后:
public class Application : IApplication { private readonly List<Requester> _requesters = []; public Application(IRequesterFactory requesterFactory) { _requesters.AddRange(requesterFactory.CreateRequesters()); } public void RequestFiles() { foreach(Requester requester in _requesters) { requester.RequestFiles(); } } }
这样整个流程就完整了:DI容器注入工厂,工厂根据XML配置动态创建Requester实例,Application只负责调用实例方法,完全符合DI和IoC的设计原则。
内容的提问来源于stack exchange,提问作者Álvaro García
相关产品推荐
相关产品推荐

