在使用IoC容器时,原始构造函数参数是一个坏主意吗?

标准新手免责声明:我是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
    }
}

这种方法甚至可以调整到Facade服务(以前称为综合服务),正如Mark Seemann在这里所提到的。

我也读过,你可以使用这些值的属性,并使用属性注入,但它似乎不再是首选(autofac提到构造函数注入是首选... Ninject我相信,即使删除了版本2中的能力)。

或者我读过,你也可以创建一个初始化方法,并确保在那里设置属性。

这么多的选择,我越来越困惑,因为我更多地了解这个东西。 我相信没有确切的正确方法(或者,至少在这个例子中是这样的),但也许有人可以提供每种方法的优点和缺点。 或者也许还有另一种我完全错过的方法。

我现在意识到,这个问题可能在主观方面有点(并且实际上不止一个问题),但我希望你能原谅我并提供一些指导。

PS - 我目前正在尝试使用autofac,以防影响哪种设计更适合。

注意:我对目标文件夹的代码进行了轻微更改...它不被RenameFiles使用(可能与您的答案有关)。


那么在阅读.Net中的Dependency Injection之后,我最终重新设计了这本书(我强烈推荐本书适用于任何面向对象的开发人员,而不仅仅是.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命名参数来处理它们。

所以我想回答我自己的问题,如果它们合理,基本的构造函数参数是一个好主意,但要确保将它们放在它们所属的位置。 如果事情似乎没有妥善处理,可以通过重新考虑设计来改善。


在你的例子中,你实际传递的是依赖关系,而且还有类需要的数据操作。

在你的情况下,听起来像RenameFiles()CopyFiles()对传递给它们的参数进行操作。 考虑到他们的名字,我认为可以用不同的参数调用ImageFileGenerator的单个实例上的方法。 如果这是真的,那么参数应该在方法上调用它们自己而不是构造函数。

另一方面,如果在一个实例中RenameFiles()CopyFiles()每个只使用相同的参数调用一次,那么这些参数将成为构造函数的良好候选者。

我个人会试图避免所需的依赖项的属性注入 - 在这种情况下,构造函数注入更合适。

链接地址: http://www.djcxy.com/p/82143.html

上一篇: Are primitive constructor parameters a bad idea when using an IoC Container?

下一篇: Which IoC Container to use?