使用 IoC 容器时,原始构造函数参数是否一个坏主意? [关闭]
Posted
技术标签:
【中文标题】使用 IoC 容器时,原始构造函数参数是否一个坏主意? [关闭]【英文标题】:Are primitive constructor parameters a bad idea when using an IoC Container? [closed]使用 IoC 容器时,原始构造函数参数是不是一个坏主意? [关闭] 【发布时间】:2011-12-31 11:07:39 【问题描述】:标准新手免责声明:我是 IoC 新手,收到的信号不一。我正在寻找有关以下情况的一些指导。
假设我有以下接口和实现:
public interface IImageFileGenerator
void RenameFiles();
void CopyFiles();
public class ImageFileGenerator : IImageFileGenerator
private readonly IList<IImageLink> _links;
private readonly string _sourceFolder;
private readonly string _destinationFolder;
private readonly int _folderPrefixLength;
public ImageFileGenerator(IList<IImageLink> links, string sourceFolder, string destinationFolder)
_links = links;
_sourceFolder = sourceFolder;
_destinationFolder = destinationFolder;
_folderPrefixLength = 4;
public void RenameFiles()
// Do stuff, uses all the class fields except destination folder
public void CopyFiles()
// Do stuff, also uses the class fields
我很困惑是否应该只将接口/依赖项发送给构造函数,创建一些参数对象并将其传递给构造函数,还是保持原样并在解析实例时传递参数。
那么有没有更正确的方法来设置此代码以最好地与 IoC 容器配合使用?与我当前的布局相比,以下哪一项在设计上更受欢迎?
1.
public interface IImageFileGenerator
void RenameFiles(IList<IImageLink> links, string sourceFolder);
void CopyFiles(IList<IImageLink> links, string sourceFolder, stringDestFolder);
public class ImageFileGenerator : IImageFileGenerator
private readonly int _folderPrefixLength;
public ImageFileGenerator()
_folderPrefixLength = 4;
public void RenameFiles(IList<IImageLink> links, string sourceFolder)
// Do stuff
public void CopyFiles(IList<IImageLink> links, string sourceFolder, stringDestFolder)
// Do stuff
我不喜欢在两种情况下都传递完全相同的东西(目标文件夹除外)。在 IImageFileGenerator 的当前实现中,我需要执行这两个方法,并且每个方法都需要相同的值。这就是我通过构造函数传入状态的原因。
2.
public interface IImageFileGenerator
void RenameFiles();
void CopyFiles();
public class ImageLinkContext
// various properties to hold the values needed in the
// ImageFileGenerator implementation.
public class ImageFileGenerator : IImageFileGenerator
private readonly IList<IImageLink> _links;
private readonly string _sourceFolder;
private readonly string _destinationFolder;
private readonly int _folderPrefixLength;
public ImageFileGenerator(ImageLinkContext imageLinkContext)
// could also use these values directly in the methods
// by adding a single ImageLinkContext field and skip
// creating the other fields
_links = imageLinkContext.ImageLinks;
_sourceFolder = imageLinkContext.Source;
_destinationFolder = imageLinkContext.Destination;
_folderPrefixLength = 4;
public void RenameFiles()
// Do stuff, uses all the class fields except destination folder
public void CopyFiles()
// Do stuff, uses all the class fields
这种方法甚至可以调整为 Mark Seemann here 提到的外观服务(以前称为聚合服务)。
我还读到您可以为这些值使用属性并使用属性注入,尽管这似乎不再是首选(autofac 提到构造函数注入是首选... Ninject 我相信甚至删除了版本 2 中的功能)。
另外,我读到您还可以创建一个初始化方法并确保在其中设置属性。
有这么多的选择,当我阅读更多关于这些东西的信息时,我变得越来越困惑。我敢肯定没有明确的正确方法(或者至少对于这个例子来说可能有?),但也许有人可以提供每种方法的优缺点。或者也许还有另一种我完全错过的方法。
我现在意识到这个问题可能有点主观(实际上不仅仅是一个问题),但我希望你能原谅我并提供一些指导。
PS - 我目前正在尝试使用 autofac,以防影响哪种设计可能更适合。
注意:我对目标文件夹的代码做了一些细微的更改...... RenameFiles 不使用它(可能对您的回答有影响)。
【问题讨论】:
这里是关于注入 services 与 data 的相关讨论:***.com/questions/1818539/… @Peter Lillevold:有趣,我会花一些时间看看工厂代表。我可以看到它们派上用场。感谢您的链接(以及您回答中的附加文章:peterspattern.com/generate-generic-factories-with-autofac)。 【参考方案1】:好吧,在阅读了 Dependency Injection in .Net 这本书后,我最终重新设计了这本书(我强烈推荐这本书给任何面向对象的开发人员,不仅仅是 .Net 开发人员,也不仅仅是那些对使用 IoC 容器感兴趣的人!)。
我现在在域程序集中获得了以下内容:
public interface IImageFileService
void RenameFiles();
void CopyFiles();
public interface IImageLinkMapRepository
IList<ImageLink> GetImageLinks();
然后在 FileAccess 程序集中,我为这些接口创建了实现:
public class ImageFileService : IImageFileService
public ImageFileService(IImageLinkMapRepository repository)
// null checks etc. left out for brevity
_repository = repository;
public void RenameFiles()
// rename files, using _repository.GetImageLinks(), which encapsulates
// enough information for it to do the rename operations without this
// class needing to know the specific details of the source/dest dirs.
public void CopyFiles()
// same deal as above
所以本质上,我已经在构造函数中消除了对原始类型的需求,至少对于这个类来说是这样。在某些时候,我确实需要这些信息,但它被注入到 ImageLinkMapRepository 中,其中信息更有意义。我使用autofac named parameters 处理注入它们。
所以我想回答我自己的问题,如果它们有意义,原始构造函数参数是一个好主意,但请确保将它们放在它们所属的位置。如果事情似乎不正常,可能可以通过重新考虑设计来改进。
【讨论】:
【参考方案2】:在您的示例中,您实际传递的是 依赖项,但此外,该类需要 data 进行操作。
在您的情况下,听起来RenameFiles()
和CopyFiles()
方法对传递给它们的参数进行操作。鉴于它们的名称我认为ImageFileGenerator
的单个实例上的方法可以使用不同的参数调用。如果这是真的,那么参数应该在方法调用本身而不是构造函数上。
另一方面,如果在一个实例上 RenameFiles()
和 CopyFiles()
仅使用相同的参数调用一次,则参数将是构造函数的良好候选者。
我个人会尽量避免 必需 依赖项的属性注入 - 在这种情况下,构造函数注入更合适。
【讨论】:
目前的用法是两者都只被调用一次并且具有相同的参数值。我们很可能会一直调用RenameFiles,然后立即调用CopyFiles。我想我可以将它们组合成一个公共方法,然后将它们都设为私有。我试图拆分功能以便于进行单元测试。 @JasonDown:在那种情况下,我认为您回答了自己的问题。此外,如果您传入的数据确实只有一个操作,您可以将其移动到静态方法中。 绝对值得考虑。考虑负载...实际上很有可能需要另一个接口的实现,它只会复制图像...并且会有不同的源和目标(它将是复制图像,但副本将转换为缩略图大小)。所以也许将参数传递给每个方法是要走的路。以上是关于使用 IoC 容器时,原始构造函数参数是否一个坏主意? [关闭]的主要内容,如果未能解决你的问题,请参考以下文章