25 votos

Son primitivas, los parámetros del constructor es una mala idea cuando se utiliza un Contenedor de IoC?

Estándar novato descargo de responsabilidad: soy nuevo en el Coi y estoy recibiendo señales mixtas. Estoy buscando un poco de orientación en la siguiente situación, por favor.

Supongamos que tengo la siguiente interfaz y la implementación:

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
    }
}

Yo estoy confundido si debo enviar sólo la interfaz o las dependencias en el constructor, a crear algunos de los parámetros objeto y pasar al constructor o mantenerlo como está y pasar los parámetros en el momento de la resolución de una instancia.

Entonces, ¿hay una manera más correcta de la creación de este código funcione mejor con un contenedor de IoC? Sería de la siguiente diseño preferido-sabio sobre mi diseño actual?

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
    }
}

No me gusta que me estoy pasando exactamente lo mismo en ambos casos (a excepción de la carpeta de destino). En la implementación actual de la IImageFileGenerator, necesito para ejecutar los métodos y los mismos valores que fueron necesarios para cada método. Es por eso que pasé por el estado a través del constructor.

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
    }
}

Este enfoque puede incluso ser ajustados para una Fachada de Servicio (anteriormente llamado los servicios de agregado), como lo menciona la Marca Seeman aquí.

También he leído que usted podría utilizar las propiedades de los valores y el uso de la propiedad de la inyección, aunque parece que no es el preferido (autofac menciona constructor es preferible la inyección... Ninject creo que incluso eliminado la posibilidad en la versión 2).

Alternativamente, he leído que también se puede crear un método de inicialización y asegurarse de que las propiedades se establecen allí.

Así que muchas opciones y yo estoy cada vez más confundido como yo leer más acerca de esto. Estoy seguro de que no hay un definitivo manera correcta (o tal vez no hay, al menos para este ejemplo???), pero tal vez alguien puede dar pros y los contras de cada enfoque. O tal vez hay otro enfoque que he totalmente perdido.

Ahora me doy cuenta de que esta pregunta es probablemente un poco en el lado subjetivo (y es realmente más de una pregunta), pero espero que puedas perdonarme y proporcionar alguna orientación.

PS - actualmente estoy tratando de que mi mano con la autofac en caso de que influye en las que el diseño puede hacer que se ajuste mejor.

NOTA: he hecho un ligero cambio en el código sobre la carpeta de destino... no es utilizado por RenameFiles (puede tener un impacto en su respuesta).

13voto

Jason Down Puntos 13690

Así terminé el rediseño de este después de leer el libro de la Inyección de Dependencia .Neto (yo recomiendo este libro a cualquier objeto-orientado a desarrolladores, no sólo .Neto de los desarrolladores y no sólo a aquellos interesados en el uso de un contenedor de IoC!).

Ahora tengo la siguiente en un Dominio de la asamblea:

public interface IImageFileService
{
    void RenameFiles();
    void CopyFiles(); 
}

public interface IImageLinkMapRepository
{
    IList<ImageLink> GetImageLinks(); 
}

A continuación, en un FileAccess asamblea he creado las implementaciones de estas interfaces:

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
    }
}

Así que, esencialmente, he eliminado la necesidad de que los tipos primitivos en mi constructor, al menos para esta clase. En algún momento me hizo necesario que la información, sino que se inyecta en el ImageLinkMapRepository donde la información más sentido. He utilizado autofac llamado parámetros para controlar la inyección de ellos.

Así que supongo que para responder a mi propia pregunta, primitivo parámetros del constructor son una buena idea si tienen sentido, pero asegúrese de que usted ponga donde ellos pertenecen. Si las cosas no parecen ser jiving correctamente, probablemente puede ser mejorada mediante el replanteamiento del diseño.

2voto

BrokenGlass Puntos 91618

En tu ejemplo, lo que realmente está pasando son las dependencias, sino que además los datos necesarios por la clase para operar.

En tu caso suena como los métodos RenameFiles() y CopyFiles() operar en los parámetros que se pasan a ellos. Sus nombres yo creo que los métodos en una sola instancia de ImageFileGenerator puede ser llamado con diferentes parámetros. Si que es cierto podría decirse que los parámetros deben estar en las llamadas al método en sí no es el constructor.

Si, por otro lado, en un ejemplo RenameFiles() y CopyFiles() son cada uno solo se llama una vez con los mismos parámetros los parámetros serían buenos candidatos para el constructor.

Yo personalmente intentaría evitar propiedad de la inyección para la necesaria dependencias - en ese caso inyección de constructor es mucho más apropiado.

Iteramos.com

Iteramos es una comunidad de desarrolladores que busca expandir el conocimiento de la programación mas allá del inglés.
Tenemos una gran cantidad de contenido, y también puedes hacer tus propias preguntas o resolver las de los demás.

Powered by:

X