我正在编写一个简单的控制台应用程序,它负责连接到数据库、从中选择特定产品(基于提供的标准)并使用该产品进行一些处理。我将命令行参数存储到此类的一个实例:
public class Arguments
{
public string ConnectionString { get; set; }
public int ProductId { get; set; }
public string ProductName { get; set; }
}
在某些时候,我需要从数据库中获取产品。我为此使用以下存储库:
public interface IProductRepository
{
Product GetById(int productId, string connectionString);
Product GetByName(string productName, string connectionString);
}
然后,我将存储库的实现注入到使用它的类中,例如:
public class ProductProcessor
{
private readonly IProductRepository productRepository;
public ProductProcessor(IProductRepository productRepository)
{
this.productRepository = productRepository;
}
public void Process(Arguments arguments)
{
Product productToProcess;
if (!string.IsNullOrEmpty(arguments.ProductName))
{
productToProcess = productRepository.GetByName(arguments.ProductName, arguments.ConnectionString);
}
else
{
productToProcess = productRepository.GetById(arguments.ProductId, arguments.ConnectionString);
}
// ....
}
}
这是有效的,但我不喜欢这个设计的是每个方法IProductRepository
都有一个connectionString
参数。如果不涉及依赖注入,我可能会像下面这样重写它:
public void Process(Arguments arguments)
{
Product productToProcess;
ProductRepository productRepository = new ProductRepository(arguments.ConnectionString);
if (!string.IsNullOrEmpty(arguments.ProductName))
{
productToProcess = productRepository.GetByName(arguments.ProductName);
}
else
{
productToProcess = productRepository.GetById(arguments.ProductId);
}
// ....
}
这使我能够拥有更简单、更易于使用的界面。当然,现在ProductRepository
没有无参数构造函数,很难与 DI 容器一起使用。理想情况下,我希望两全其美,即ProductRepository
使用构造函数中的连接字符串进行初始化,并从其方法中删除连接字符串。实现这一目标的最佳方法是什么?
我已经考虑过的一些方法:
- 将一个方法添加
Initialize(string connectionString)
到IProductRepository
基本上可以用作构造函数的方法。明显的缺点是我现在需要检查在或方法Initialize
中做任何事情之前是否已经调用了。GetById
GetByName
- 不要使用构造函数注入,而是使用服务定位器模式来实例化
ProductRepository
. 我不太喜欢 Service Locator,但这可能是唯一可能的解决方案。
有没有更好的选择?
编辑:从答案中我看到我应该发布更多的上下文。我使用 Ninject 作为我的 DI 容器。在Main
我的 Program.cs 中的方法中,我将所有依赖项注册到容器并实例化用作应用程序入口点的类:
public static void Main(string[] args)
{
StandardKernel kernel = new StandardKernel();
kernel.Bind<IArgumentsParser>().To<IArgumentsParser>();
kernel.Bind<IProductProcessor>().To<ProductProcessor>();
kernel.Bind<IProductRepository>().To<ProductRepository>();
MainClass mainClass = kernel.Get<MainClass>();
mainClass.Start(args);
}
MainClass
如下所示:
public class MainClass
{
private readonly IArgumentsParser argumentsParser;
private readonly IProductProcessor productProcessor;
public MainClass(IArgumentsParser parser, IProductProcessor processor)
{
argumentsParser = parser;
productProcessor = processor;
}
public void Start(string[] args)
{
Arguments parsedArguments = argumentsParser.Parse(args);
productProcessor.Process(parsedArguments );
}
}
这使我能够依赖 Ninject 并仅在一个地方(方法)创建整个图,Main
而应用程序的其余部分对 DI 和容器一无所知。
如果可能的话,我想保持这种状态。