【问题标题】:SRP, DI and app.config: when to instantiate injecting classes?SRP、DI 和 app.config:何时实例化注入类?
【发布时间】:2016-01-31 04:53:19
【问题描述】:

我正在重构一个小型报告生成应用程序,并使其符合 SOLID 原则等。因此,我所有的类都遵循带有 DI 的 SRP,并且我使用 app.config 来处理大多数参数变化。我还没有使用任何 DI 框架,而是在应用程序入口点创建所有依赖类。然而,这导致了一个设计问题,我在这里概括一下:

我可以像这样创建我的依赖项和主要报告类:

//dependencies    
var sharedDependency = new SharedDependency();

var whiteColorDependency = new ColorDependency("white");
var blueColorDependency = new ColorDependency("blue");

var config1Dependency = new MultiDependency("config1");
var config2Dependency = new MultiDependency("config2");
...
var config12Dependency = new MultiDependency("config12");



//main logic
var reporter1 = new Reporter(sharedDependency, whiteColorDependency, config1Dependency);
var reporter2 = new Reporter(sharedDependency, whiteColorDependency, config2Dependency);
var reporter3 = new Reporter(sharedDependency, whiteColorDependency, config3Dependency);
...
var reporter10 = new Reporter(sharedDependency, blueColorDependency, config10Dependency);
var reporter11 = new Reporter(sharedDependency, blueColorDependency, config11Dependency);
var reporter12 = new Reporter(sharedDependency, blueColorDependency, config12Dependency);

或类似:

foreach (var config in configs)
{
    //dependencies
    var sharedDependency = new SharedDependency();
    var colorDependency = new ColorDependency("color");
    var configDependency = new MultiDependency("config");

    //main logic
    var reporter = new Reporter(sharedDependency, colorDependency, configDependency);
    reporter.DoSomething();
}

?

(“colors”和“config”的值都是来自app.config文件,不是硬编码的。上面说的是概括,实际项目有更多依赖关系,依赖关系的依赖关系,其中一些比其他的共享更多。)

第一种方法效率更高,因为 CSharedDependency 只创建一次,CColorDependency 只创建两次。 (它对我来说也更具可读性。)不过,第二个是完全配置驱动的,因此需要零维护并且完全可扩展。

那么,哪一个是最好的设计?

【问题讨论】:

  • 为什么不能结合这两种方法?您不能在循环之外创建共享依赖项吗?我不清楚这个问题,因为循环替代方案不使用config...
  • @MarkSeemann 循环替代方案确实将.config 用于“颜色”和“配置”值 - 这是我的问题。我可以在循环之外创建共享依赖项吗?是的,这就是方法 1。问题在于我必须明确指定哪些Reporters 使用whiteColorDependency,哪些使用blueColorDependency。所以,如果我要添加另外两个(或五个)Reporters,我必须修改代码。使用循环方法,这一切都完全由.config 驱动并且非常可扩展......但是,我必须拥有 12 个以上的 ColorDependency 实例而不是 2 个。
  • “循环替代方案确实使用.config。在哪里?
  • "white", "blue" 真的来自ConfigurationManager.AppSettings["white"], ConfigurationManager.AppSettings["blue"]。 “config1”到“config12”也一样。

标签: c# dependency-injection configuration-files solid-principles single-responsibility-principle


【解决方案1】:

为依赖注入组织应用程序的正确方法(无论是使用容器还是pure DI)是在应用程序启动时使用Composition Root 来组成应用程序的对象图。

因此,您的第一个示例看起来更符合这一点,因为您永远不会在运行时访问您的容器来创建依赖项,而是使用inject abstract factories 来创建这些实例。

也就是说,从您的示例中不清楚您是如何组织应用程序的。如果没有组合根,您就没有正确地进行依赖注入。而且由于您必须提出这个问题,我怀疑您没有组合根,因为如果您这样做,您的第二个示例将永远无法工作。

参考资料:

https://www.kenneth-truyers.net/2014/11/18/how-to-use-pure-di/

【讨论】:

  • 如果您查看您提供的参考资料的“控制台应用程序中的纯 DI”部分,这正是我所拥有的:一个带有纯 DI 和依赖项构造的控制台应用程序就在 main( )。 “entryPoint.Run()”基本上是我的“reporter.DoSomething()”。唯一的区别是我有 12 个“记者”。因此,我的问题是——我是为我的“组合根”编写一个不灵活但更有效的逻辑,还是一个非常简洁的逻辑,它会创建不必要的共享依赖项实例。不过,您的抽象工厂建议给了我一个想法,所以我会研究一下。谢谢
【解决方案2】:

据我了解这个问题,令人担忧的是,在第二种选择中,SharedDependency 被创建了多次,并且ColorDependency 实例的创建次数也超过了必要的次数。

我对此的第一反应是可能并不重要。如果您遵循constructors should do no work 的规则,那么创建一些不必要的对象很可能是您不会注意到的——特别是如果这些对象随后参与 I/O。 .NET 中的对象创建(I/O 很慢)。

也就是说,“问题”可能很容易解决。

如果您希望完全由配置驱动,则需要一种方法来区分不同的配置值组。最简单的方法最有可能在 appSettings 键前面加上众所周知的前缀,但更稳健的方法是定义自定义配置部分。

无论如何,我假设您可以从配置系统中提取两个集合:colorsconfigs

这将使以配置驱动的方式创建服务变得容易:

var sharedDependency = new SharedDependency();
foreach (var color in colors)
{
    var colorDependency = new ColorDependency(color);

    foreach (var config in configs)
    {
        var configDependency = new MultiDependency(config);

        //main logic
        var reporter = new Reporter(sharedDependency, colorDependency, configDependency);
        reporter.DoSomething();
    }
}

说了这么多,在您开始重新发明轮子之前:大多数 DI 容器都支持通过 app.config 进行配置,所以这也可能是您的一个选择。

再说一遍:那个说,毕竟考虑一下using a DI Container is an appropriate choice。使用基于文本的配置,您将丢失benefit of compile-time checking。您也可以轻松结束making the configuration system so complicated that code would be easier

除非您有令人信服的理由在配置文件中配置对象图,否则请支持Pure DI

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-08-30
    • 1970-01-01
    • 2022-07-19
    • 2020-10-13
    相关资源
    最近更新 更多