Descargo de responsabilidad estándar para novatos: Soy nuevo en IoC y estoy recibiendo señales mixtas. Estoy buscando orientación sobre la siguiente situación, por favor.¿Los parámetros de constructor primitivo son una mala idea cuando se utiliza un contenedor de IoC?
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
}
}
Me estoy confundido si sólo debería enviar interfaz/dependencias con el constructor, cree un objeto de parámetro y pasarlo al constructor o mantenerlo como está y pasa los parámetros en el momento de resolver una instancia.
¿Hay una forma más correcta de configurar este código para que funcione mejor con un contenedor IoC? ¿Sería preferible alguna de las siguientes opciones de diseño 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 estoy pasando exactamente lo mismo en ambos casos (excepto la carpeta de destino). En la implementación actual de IImageFileGenerator, necesito ejecutar ambos métodos y se necesitan los mismos valores para cada método. Es por eso que pasé el estado en el 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 ajustado a un Servicio de Fachada (anteriormente llamado servicios agregados) como se ha mencionado por Mark Seemann here.
También he leído que podría usar propiedades para esos valores y usar inyección de propiedad, aunque parece que ya no se prefiere (autofac menciona que la inyección del constructor es preferible ... Ninject Creo que incluso eliminó la capacidad en la versión 2).
Como alternativa, he leído que también puede crear un método de inicialización y asegurarse de que las propiedades estén establecidas allí.
Tantas opciones y cada vez me siento más confundido a medida que leo más sobre esto. Estoy seguro de que no hay una forma definitiva y correcta (¿o tal vez lo hay, al menos para este ejemplo?), Pero tal vez alguien pueda proporcionar los pros y los contras de cada enfoque. O tal vez hay otro enfoque que me he perdido totalmente.
Me doy cuenta ahora de que esta pregunta es, probablemente, un poco subjetiva (y en realidad es más de una pregunta), pero espero que me puedas perdonar y brindar alguna orientación.
PD - Actualmente estoy probando mi mano con autofac en caso de que influya en qué diseño puede caber mejor.
NOTA: He realizado un ligero cambio en el código sobre la carpeta de destino ... RenameFiles no lo usa (puede influir en su respuesta).
Aquí hay una discusión relacionada sobre cómo inyectar * servicios * vs * datos *: http://stackoverflow.com/questions/1818539/how-to-pass-controllers-modelstate-to-my-service-constructor-with-autofac –
@Peter Lillevold: Interesante, voy a pasar un tiempo mirando a los delegados de la fábrica. Veo que son útiles. Gracias por el enlace (y el artículo adjunto en su respuesta: http://peterspattern.com/generate-generic-factories-with-autofac/). –