【问题标题】:Dependency Injection/config object依赖注入/配置对象
【发布时间】:2012-08-24 03:57:55
【问题描述】:

我有一个对象负责将文件导出到 csv。

它运作良好,但我正在寻找重构它的方法。

这个问题与构造函数有关,它带有许多参数,与如何导出 csv 有关:

例如文件名、分隔符等。

另外,最近我一直在阅读有关依赖注入的内容,但无法确定是否应该这样做:

A.保持构造函数不变。 B. 创建一个新类,该类被传递给简单地保存文件名等配置值的构造函数 C. 完全不同的东西?

这是现有的构造函数(在 PHP 中)

    public function __construct($file,$overwriteExistingFile, $enclosure, $delim, $headerRow)
    {
        //set all properties here
    }

【问题讨论】:

  • 可能应该发布一些上下文代码。您是否需要重构它,或者这只是一个智力练习?如果它按原样运行良好,那么您可能不需要重新(过度)工程,除非它以某种方式与其他代码紧密耦合。
  • 发布现有的构造函数,我们很乐意看看。
  • 这是一种智力练习,试图学习做这类事情的最佳方法
  • @BryanWatts 谢谢我已经为你更新了。再次感谢

标签: oop design-patterns dependency-injection


【解决方案1】:

这些值中的每一个都代表作为某个流程输入的数据。 $enclosure$delimiter$headerRow 用于生成 CSV 内容,而$file$overwriteExistingFile 用于将内容保存到磁盘。

DI 风格重构的一个标志是识别各种职责(生成、持久化)并将每个它们封装在自己的类型中。这将重构从“我如何最好地将值 转换为 这个类?”到“我如何从这个类中删除这些值的知识?”

为了回答这个问题,我们将定义两个新概念,每个概念承担一个职责,并将它们传递给现有的构造函数:

public function __construct($csvGenerator, $csvFileWriter)
{
    ...save dependencies...
}

...at some point, generate the CSV content and pass it to the file writer...

通过这种方式,原始类成为生成和文件写入之间交互的协调者,而无需对任何一个活动都有深入的了解。我们已将该类提升到更高的抽象级别,对其进行简化并将其职责隔离到其协作者中。

现在,您将定义两个 new 类,并使用相关参数构造它们:

生成器

public function __construct($enclosure, $delimiter, $headerRow)

文件编写器

public function __construct($file, $overwriteExistingFile)

有了这些元素,您可以通过创建生成器,然后是文件编写器,然后将两者传递给协调器来将它们组合在一起。

【讨论】:

  • 这听起来很有趣也很有道理。这种编码风格是否接受了让事情正常工作的更多前期工作。例如,而不是 $csvClass = new CsvClass('myacefile.csv' etc etc);我们现在有两个初始化另外两个对象,然后初始化 csvclass。那么这样做还可以吗?
  • @user1189880:是的,这是一种公认​​的编码风格。它将您的应用程序分为两个阶段:组合阶段,然后是执行阶段。您通常会有一个 DI 容器来帮助您进行合成,如果您一直在阅读有关 DI 的文章,您无疑会遇到这个概念。
  • @user1189880:此外,这种风格会产生更小的逻辑块,可以以有趣的方式组合。例如,既然 CSV 生成与 CSV 文件写入分离,您可以生成 CSV 内容并执行诸如在 UI 中显示或将其发送到 Web 服务等操作。或者,您可以使用预先生成的 CSV 内容编写文件。
  • 非常感谢您的回答,对我来说非常有意义。关于您的评论,我有最后一个问题:如果我正在创建您的回答中描述的类以及与 csv 编写器一起工作所需的其他一些服务,那么这对于容器来说是否是一个好情况?所以我会为每个逻辑部分初始化一个容器或单独的容器?
  • 通常你会为整个应用程序提供一个容器,然后请求一个根对象(有关更多信息,请参阅blog.ploeh.dk/2011/07/28/CompositionRoot.aspx)。但是,如果您有一个要添加 DI 的现有应用程序,那么在您的情况下拥有多个容器可能会很好。只是不要混合其中的对象 - 对于给定的工作只有一个容器有效。
【解决方案2】:

我会创建一个CSVFormatter,您可以使用它设置分隔符并对格式进行独立的单元测试。

将格式化程序注入CSVWriter,它将格式化的输出写入文件。

您这样做的原因是为了对格式化逻辑进行单元测试,或者如果您需要进行多种格式化或写入不同类型的输出流。如果代码非常小而且简单,那么您不需要将其分解为多个类。

【讨论】:

  • 这是我在问题中对 B 点的想法。我考虑的问题是,我仍然需要创建该对象并将分隔符等所需的值传递给它的构造函数。如果你明白我的意思吗?
  • 如果您主要关心的是构造函数中参数的数量,您可以使它们成为可以设置的字段并使用默认值。例如,',' 可以是默认分隔符,但您可以使用 setDeliminator 方法。你也可以introduce a parameter object,但这在这里可能没有意义。
  • 它不是参数的数量,而是使用对象(我需要一个类似的构造函数)来传递而不是使用构造函数的优缺点
猜你喜欢
  • 2023-04-09
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-01-03
  • 1970-01-01
  • 2021-08-04
  • 2013-03-03
  • 2023-03-20
相关资源
最近更新 更多