【问题标题】:Clean Code: Dependency Injection forces procedural code, how to refactor清洁代码:依赖注入强制程序代码,如何重构
【发布时间】:2012-07-01 16:13:27
【问题描述】:

我有以下课程:

类验证器 { 私有最终 SchemaFetcher schemaFetcher; @注入 验证器(SchemaFetcher schemaFetcher){...} } 类 DatabaseSchemaFetcher 实现 SchemaFetcher { @Override Schema loadSchema(final SchemaDefinition schemaDef); @Override boolean compareSchemaWithSource(final SchemaDefinition schemaDef, final Schema updatedSchema); }

这只是示例之一,我还有一些类似的其他类,我将它们作为依赖项注入到其他类中。但它使我的 SchemaFetcher 类像一个单例,我不断地将 schemaDefinition 传递给它的每个方法。这似乎非常程序化,我实际上想让 SchemaDefinition 成为 DatabaseSchemaFetcher 类的实例变量,但在这种情况下,我将无法将 SchemaFetcher 对象注入到我的 Validator 类中,而我应该这样做

验证(字符串模式名称){ SchemaDefinition schemaDef = buildSchemaDefinitionFrom(schemaName); SchemaFetcher fetcher = new DatabaseSchemaFetcher(schemaDef); }

但这让我与 fetcher 紧密耦合,这就是我想首先使用依赖注入的原因。

我可以看到我可能有一个 DatabaseSchemaFetcher 的默认构造函数,然后是一个 setSchemaDefintion() 设置器来实现这一点,但这违反了完全使用构造函数构建对象的原则。

如何改进这一点,使其不具有程序样式获取器,同时将我的依赖项注入构造函数?我更喜欢构造函数注入,因为它清楚地定义了我的依赖项,而无需任何人查看类的实现来找出类在我使用工厂或服务定位器时使用的依赖项。

【问题讨论】:

  • 我的建议是放松你对构造函数注入的强烈偏好。一方面,他们不允许循环依赖;另一方面,它们不允许注入延迟初始化的对象(可通过查找方法实现)。

标签: java design-patterns refactoring ooad


【解决方案1】:

依赖注入是非常好的想法之一,它看起来非常好,以至于被严重过度使用。我不会使用 DI 框架将 Fetcher 注入到验证器中。相反,我会让 DI 框架将工厂注入“main”。工厂使用适当的 SchemaDefinition 创建 Fetcher 并将其传递给 Validator。

请记住,我们想要一个将“main”与应用程序的其余部分分开的边界,并且所有依赖项都应该从“main”指向应用程序。应用程序不应该知道“main”。即“main”是应用程序的插件。

一般来说,应该使用 DI 来注入“main”,然后 main 使用更传统的技术将工厂、策略或只是常规的旧抽象接口传递到应用程序中。

【讨论】:

    【解决方案2】:

    为什么说您在第二个解决方案中与 SchemaFetcher 紧密耦合?
    您在那里提供了一个接口,因此您不会与任何特定的实现耦合,而只是与 SchemaFetcher 的定义(即 SchemaFetcher 的合同)
    您可以考虑拥有一个 Validator 类,该类将 SchemaDefinition 纳入其 CTOR,并且您的 DatabaseSchemaFetcher 可以为其保存一个字段。这样,如果需要,您还可以扩展 Validator 类更改验证逻辑。
    但是,如何传递模式定义对象的问题又一次出现了。不确定是否应该在此处使用注入 - 考虑更改您的设计。

    【讨论】:

      【解决方案3】:

      在这种情况下,我不确定Dependecy InjectionProcedural 的使用有什么关系。

      我认为真正的问题是您选择的对象建模方式并未反映既定目标。

      在您提供的代码中Validator 没有任何用处,我看不到。如果它的目的是验证SchemaFetcher 对象,那么它可能不应该有超出验证规则的状态,然后接受任意SchemaFetcher 对象进行验证。

      至于DataBaseSchemaFetcher,我再次难以理解它的作用。如果它声明的目的只是获取模式,那么它不需要关于DatabaseSchema 对象的状态,因此应该接受DatabaseSchema 用于处理DatabaseSchema 的方法。任何内部状态都应该只与类的获取行为有关。

      克服这些painted in a corner 情况的一种尝试过且真正的方法是坐下来,非常努力地为每个班级分配一个单一的职责,并牢记以下几点:

      1. 关于您要解决的确切问题的领域真的很难。

      2. 不要解决任何你没有的问题。把你的可扩展性梦想扔掉。他们几乎总是错的,只会浪费大量时间。

      3. 接受您的设计必然有缺陷,您将不得不稍后更改它。

      【讨论】:

        猜你喜欢
        • 2019-03-28
        • 1970-01-01
        • 1970-01-01
        • 2022-01-02
        • 1970-01-01
        • 2012-04-23
        • 2016-12-22
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多