DI-Container:如何将配置传递给对象

时间:2010-02-19 16:32:52

标签: dependency-injection inversion-of-control

有时我会有一些课程需要获取一些建筑信息。我不是在谈论对其他对象(将被注入)的引用,而是关于(例如)包含唯一信息的字符串:

// Scoped as singleton!
class Repository
{
    public Repository( InjectedObject injectedObject, string path ) { ... }
}

你如何注入这个字符串?一种可能性是编写Init()方法并避免注入字符串:

class Repository
{
    public Repository( InjectedObject injectedObject ) { ... }
    public void Init( string path ) { ... }
}

另一种可能性是将信息包装到一个可以注入的对象中:

class InjectedRepositoryPath
{
    public InjectedRepositoryPath( string path ) { ... }
    public string Path { get; private set; }
}

class Repository
{
    public Repository( InjectedObject injectedObject, InjectedRepositoryPath path ) { ... }
}

这样我就必须在初始化DI-Container时创建InjectedRepositoryPath的实例并注册这个实例。但我需要为每个类似的类提供这样一个独特的配置对象。

当然我可以解析RepositryFactory而不是Repository对象,因此工厂会问我路径:

class RepositoryFactory
{
    Repository Create( string path ) { ... }
}

但同样,这是一个仅用于单件对象的工厂......
或者,最后,由于路径将从配置文件中提取,我可以跳过传递字符串并在构造函数中读取配置(这可能不是最佳,但可能):

class Repository
{
    public Repository( InjectedObject injectedObject )
    {
        // Read the path from app's config
    }
}

你最喜欢的方法是什么?对于非单例类,您必须使用imho Init()或工厂解决方案,但是单例范围的对象呢?

2 个答案:

答案 0 :(得分:3)

如果您正在使用构造函数注入,我发现添加一个参数是构造函数的配置对象,这是最好的方法。通过使用init函数,您可以稍微回避构造函数注入的问题。这使得测试更加困难,也使维护和交付更加困难。

发现成为一个问题,因为这个类需要一个配置对象并不是很明显。通过将它添加到构造函数中,使用此对象的任何人都明确知道此配置必须存在。

答案 1 :(得分:2)

我更喜欢没有DI容器来决定我的API设计。容器应符合适当的设计,而不是相反。

DI-friendly方式设计您的课程,但不对您的DI容器做出让步。如果需要连接字符串,则通过构造函数获取字符串:

public class Repository : IRepository
{
    public Repository(string path) { //... }
}

许多DI容器可以处理原始值。举个例子,这是使用Windsor的一种方法:

container.Register(Component.For<IRepository>()
    .ImplementedBy<Repository>()
    .DependsOn( new { path = "myPath" } ));

但是,如果您选择的容器无法处理原始参数,您始终可以使用知道如何查找字符串的实现来装饰Repository

public class ConfiguredRepository : IRepository
{
    private readonly Repository decoratedRepository;

    public ConfiguredRepository()
    {
        string path = // get the path from config, or whereever appropriate
        this.decoratedRepository = new Repository(path);
    }

    // Implement the rest of IRepository by
    // delegating to this.decoratedRepository
}

现在,您只需告诉容器将IRepository映射到ConfiguredRepository,同时仍保持核心存储库实现的清洁。