【问题标题】:DI-Container: Howto pass configuration to objectsDI-Container:如何将配置传递给对象
【发布时间】:2011-01-18 20:49:09
【问题描述】:

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

// 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
    }
}

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

【问题讨论】:

    标签: dependency-injection inversion-of-control


    【解决方案1】:

    如果您使用构造函数注入,我发现向构造函数添加一个作为您的配置对象的参数是最好的方法。通过使用 init 函数,您在某种程度上回避了构造函数注入的点。这使测试更加困难,也使维护和交付更加困难。

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

    【讨论】:

      【解决方案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,同时仍然保持核心存储库实现干净。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-06-12
        • 1970-01-01
        • 2011-12-28
        • 2013-07-13
        • 2023-03-06
        • 2012-01-30
        相关资源
        最近更新 更多