7

Quería evitar la instrucción de cambio. Tengo más de 30 tipos de documentos. También existe la posibilidad de que necesite agregar más tipos de documento en el futuro. Prefiero pasar IDocument y tener el tipo especificado en la implementación de IDocument. Otra cosa que olvidé mencionar fue ProgressNoteViewModel, LabViewModel ... todos heredan de WorkspaceViewModel y todos los constructores de implementación concretos toman un tipo IPatient como parámetro. También estoy usando Castillo como mi contenedor IoC¿Cómo reemplazo una declaración de interruptor con IOC para poder mantener el principio SOLIDO

me quiera refactorizar el código para algo así como

viewModel = new TreeViewModel(repository.GetPatientDocumentListing(IDocumentType); 
this.DocTreeViewModel = viewModel; 
//How would I then be able to instantiate the right ViewModel 
//based on IDocumentType and also pass a object into the 
//constructor that is not know at compile time 

Tengo el siguiente código:

switch (docType) 
{ 
    case "ProgressNotes": 
     viewModel = new TreeViewModel(repository.GetPatientProgressNotes()); 
     this.DocTreeViewModel = viewModel; 
     ProgressNoteViewModel workspace = ProgressNoteViewModel.NewProgressNoteViewModel(_patient); 
     break; 
    case "Labs": 
     viewModel = new TreeViewModel(repository.GetPatientLabs()); 
     this.DocTreeViewModel = viewModel; 
     LabViewModel workspace = LabViewModel.NewLabViewModel(_patient); 
     break; 
} 
this.Workspaces.Add(workspace); 
this.SetActiveWorkspace(workspace); 
+0

Lo contenedor IoC está usando? – smaclell

Respuesta

4

totalmente no probado:

public class ViewModelBuilderFactory 
{ 
    public IViewModelBuilder GetViewModelBuilder (string docType, IRepository repository) 
    { 
     switch (docType) 
     { 
      case "ProgressNotes": 
       return new ProgressNotesViewModelBuilder(repository); 
      case "Labs": 
       return new LabsViewModelBuilder(repository); 
      default: 
       throw new ArgumentException(
        string.Format("docType \"{0}\" Invalid", docType); 
     } 
    } 
} 

public interface IViewModelBuilder 
{ 
    TreeViewModel GetDocTreeViewModel(); 
    WorkSpace GetWorkSpace(Patient patient); 
} 

public class LabsViewModelBuilder : IViewModelBuilder 
{ 
    private IRepository _repository; 
    public LabsViewModelBuilder(IRepository repository) 
    { 
     _repository = repository; 
    } 

    public TreeViewModel GetDocTreeViewModel() 
    { 
     return new TreeViewModel(_repository.GetPatientLabs()); 
    } 

    public Workspace GetWorkspace(Patient patient) 
    { 
     return LabViewModel.NewLabViewModel(patient); 
    } 
} 

public class ProgressNotesViewModelBuilder : IViewModelBuilder 
{ 
    private IRepository _repository; 
    public ProgressNotesViewModelBuilder(IRepository repository) 
    { 
     _repository = repository; 
    } 

    public TreeViewModel GetDocTreeViewModel() 
    { 
     return new TreeViewModel(_repository.GetPatientProgressNotes()); 
    } 

    public Workspace GetWorkspace(Patient patient) 
    { 
     return ProgressNoteViewModel.NewProgressNoteViewModel(patient); 
    } 
} 

Ahora su código de llamada es:

ViewModelBuilderFactory factory = new ViewModelBuilderFactory(); 
IViewModelBuilder modelBuilder = factory.GetViewModelBuilder(docType, repository); 
this.DocTreeViewModel = modelBuilder.GetDocTreeViewModel(); 
Workspace workspace = modelBuilder.GetWorkspace(patient); 
this.Workspaces.Add(workspace); 
this.SetActiveWorkspace(workspace); 

[4 ediciones desde la primera publicación; seguir viendo errores]

[Editar Además señalando que está utilizando Castillo COI]

En su configuración XML Castillo, se podría añadir (y estoy trabajando en sólo un conocimiento vago del castillo de aquí)

<component id="ProgressNotesViewModelBuilder" 
      type="MyNamespace.ProgressNotesViewModelBuilder, MyAssembly"> 
    <parameters> 
     <!-- reference to repository here --> 
    </parameters> 
</component> 
<component id="LabsViewModelBuilder" 
      type="MyNamespace.LabsViewModelBuilder, MyAssembly"> 
    <parameters> 
     <!-- reference to repository here --> 
    </parameters> 
</component> 

Entonces no es necesario el ViewModelBuilderFactory, sólo puede reemplazar

IViewModelBuilder modelBuilder = factory.GetViewModelBuilder(docType, repository); 

con

IViewModelBuilder modelBuilder = (IViewModelBuilder) 
    container.Resolve(docType + "ViewModelBuilder"); 

Ahora no necesita su declaración de interruptor en absoluto.

Sin embargo, vale la pena señalar que los interruptores no son malvados, solo huelen mal y que todos los malos olores deben aislarse de todo lo que huele bien; eso es lo que el patrón de Factory pretende lograr.

+0

Yarg golpeado por solo unos minutos. También podría hacer que cada una de las clases de ModelBuilder implemente la interfaz 'IViewModelBuilder'. Si realmente desea un contenedor IoC involucrado, podría usar docType para diferenciar las configuraciones nombradas, pero podría haber demasiada lógica de negocios configurada en el contenedor. – smaclell

+0

Quería que implementaran la interfaz, de lo contrario no tiene sentido. Editado – pdr

+0

El cambio para encajar con el Principio de inversión de control depende de 'IViewModelBuilder' en lugar de las implementaciones concretas' ProgressNotesViewModelBuilder' o 'LabsViewModelBuilder'. – smaclell

1

En lugar del contenedor de IoC, intentaría combinar patrones de estrategia y de fábrica. Si necesita parámetros de constructor personalizados para cada caso, supongo que necesita un contenedor de IoC adecuado con el cableado.

class ViewModelBuilderFactory 
{ 
    private Dictionary<string, System.Type> resolver; 

    public void ViewModelBuilderFactory() 
    { 
     resolver = new Dictionary<string, Type> 
     { 
      {"ProgressNotes", typeof(ProgressNotesViewModelBuilder)}, 
      {"Labs", typeof(LabsViewModelBuilder)} 
     }; 
    } 

    public IViewModelBuilder GetViewModelBuilder(string key) 
    { 
     System.Type type = this.resolver[key]; 
     return (IViewModelBuilder)Activator.CreateInstance(type); 
    } 

} 

EDITAR

Refiriéndose a la respuesta anterior usando el castillo de Windsor, el siguiente código podría hacer lo mismo usando componentes nombrados pero inicializados en el código:

container.Register(Component 
.For<IViewModelBuilder>() 
.ImplementedBy<ProgressNotesViewModelBuilder>() 
.Named("ProgressNotes")); 
container.Register(Component 
.For<IViewModelBuilder>() 
.ImplementedBy<LabsViewModelBuilder>() 
.Named("Labs")); 

var builder = container.Resolve<IViewModelBuilder>(key); 
Cuestiones relacionadas