2012-02-02 15 views
5

Acabo de terminar el libro inyección de dependencias de Mark Seemann en .NET y ahora estoy tratando de refactorizar algún código heredado. (En este momento, no estoy confiando en ningún contenedor DI particular, sino simplemente intentando mover todas las dependencias a un lugar).¿Cómo aplico la inyección de dependencia a una fábrica abstracta

estoy mirando a la siguiente clase de fábrica que determina la ArchiveType mediante la lectura de los primeros bytes del archivo con archiveReader.GetArchiveType() y luego devuelve una instancia de un ArchiveRestorer basado en la ArchiveType enumeración.

public class ArchiveRestorerFactory : IArchiveRestorerFactory 
{ 
    public ArchiveRestorer Create(ArchiveReader archiveReader) 
    { 
     ArchiveType type = archiveReader.GetArchiveType(); 
     switch (type) 
     { 
      case ArchiveType.CurrentData: 
       return new CurrentDataArchiveRestorer(archiveReader); 
       break; 
      case ArchiveType.HistoricalData: 
       return new HistoricalDataArchiveRestorer(archiveReader); 
       break; 
      case ArchiveType.AuditTrail: 
       return new AuditTrailArchiveRestorer(archiveReader); 
       break; 
      default: 
       throw new Exception("ArchiveRestorerFactory error: Unknown value for ArchiveType."); 
     } 
    } 
} 

¿Cómo refactorizar esto para que la clase no depende de los tipos de hormigón CurrentDataArchiveRestorer, HistoricalDataArchiveRestorer y AuditTrailArchiveRestorer?

¿Debo mover los tres restauradores de hormigón al constructor de la fábrica?

public ArchiveRestorer Create(ArchiveReader archiveReader, 
    ArchiveRestorer currentDataArchiveRestorer, 
    ArchiveRestorer historicalDataArchiveRestorer, 
    ArchiveRestorer auditTrailDataArchiveRestorer) 
{ 
    // guard clauses... 
    // assign to readonly fields 
} 

Ese parece ser el enfoque sugerido here, pero luego se va a crear una instancia de los tres restauradores cuando hace falta un único? ¿Qué pasaría si tuviera 20 implementaciones concretas posibles diferentes en su lugar?

Siento que debería implementar una fábrica de concreto para cada tipo de restaurador y devolverlo en su lugar, pero entonces simplemente reemplazaría uno new por otro.

¿Cuál es la mejor manera de refactorizar esto?

+1

Creo que su escenario podría ser más adecuado para un patrón de cadena de responsabilidad. Mire [este ejemplo] (http://davidhayden.com/blog/dave/archive/2008/11/19/ChainResponsibilityDesignPatternUnityDependencyInjectionContainer.aspx) para el uso del patrón junto con un contenedor DI específico (Unity). –

+0

No implementaría el registro y el montaje de la cadena de esa manera, pero definitivamente es un enfoque válido. –

+0

Además del uso (¿redundante?) De un 'enum', ¿qué le preocupa particularmente sobre su implementación actual? –

Respuesta

2

La forma en que lo haría, dado el código que ya tiene, sería crear una fábrica para cada uno de estos objetos que tiene un método Create().

Tendría también una interfaz para estas fábricas y las heredé de una interfaz general de fábrica.

Puede utilizar las interfaces como punto de inyección en su constructor.

Cuál sería llamado similar a esto:

case ArchiveType.CurrentData: 
       return _currentDateArchiveRestorerFactory.Create(archiveReader); 
       break; 

Alternativamente, podría ser mejor tener una sola fábrica que crea una instancia de un tipo dado. Como todos estos objetos son restauradores, puede crear la instancia basada en enum en lugar de switch.

_restorerFactory.Create(ArchiveType.CurrentData); 
1

Realice una interfaz con un método con retornos tipo de esa interfaz y dejó tres clases Archiver implementan esa interfaz y luego en el método de crear el tipo de parámetro sería sólo la interfaz y se devolverá el objeto requerido llamando el método de interfaz que acaba de crear. Entonces no necesita un tipo concreto en el método de creación.

0
interface ILogger 
{ 
    void Log(string data); 
} 

class Logger : ILogger 
{ 
    . 
    . 
    . 
} 

En este punto, se utiliza un objeto de fábrica intermedia para devolver el registrador para ser utilizado dentro del componente:

class MyComponent 
{ 
    void DoSomeWork() 
    { 
    // Get an instance of the logger 
    ILogger logger = Helpers.GetLogger(); 
    // Get data to log 
    string data = GetData(); 

    // Log 
    logger.Log(data); 
    } 
} 

class Helpers 
{ 
    public static ILogger GetLogger() 
    { 
    // Here, use any sophisticated logic you like 
    // to determine the right logger to instantiate. 

    ILogger logger = null; 
    if (UseDatabaseLogger) 
    { 
     logger = new DatabaseLogger(); 
    } 
    else 
    { 
     logger = new FileLogger(); 
    } 
    return logger; 
    } 
} 
class FileLogger : ILogger 
{ 
    . 
    . 
    . 
} 

class DatabaseLogger : ILogger 
{ 
    . 
    . 
    . 
} 
2

por qué no hacer el ArchiveReader responsable de crear el ArchiveRestorer apropiado?A continuación, la primera iteración del código se vería así:

public class ArchiveRestorerFactory : IArchiveRestorerFactory 
{ 
    public ArchiveRestorer Create(ArchiveReader archiveReader) 
    { 
     ArchiveRestorer restorer = archiveReader.GetArchiveRestorer(); 
     return restorer; 
    } 
} 

Para entonces, debería ser bastante obvio que la fábrica es redundante, por lo que en la segunda iteración del código se puede tirar a la basura dejó que los consumidores invocan el ArchiveReader directamente.

+0

Eso suena como una excelente refactorización y lo implementaré, pero no resuelve el problema de la dependencia. Mueve las dependencias a la clase 'ArchiveReader'. 'ArchiveReader.GetArchiveRestorer()' todavía necesitaría 'new' subir la subclase correcta de' ArchiveRestorer'. – shamp00

+1

Inyectarlos en el ArchiveReader. Todo se reduce a cómo selecciona el subtipo apropiado. Como no has compartido eso, es un poco difícil de responder. Sin embargo, si decide compartir eso, debería ser una nueva pregunta aquí en SO. –

+0

¿Esto no soluciona el problema de dependencia (como se menciona en el comentario anterior) y también rompe el SRP? Actualmente estoy leyendo tu libro, pero estoy atrapado con estas cosas cuando trato de aplicar las teorías al código real. – Steve

Cuestiones relacionadas