2012-07-04 22 views
8

tal vez esto es fácil, pero buscando en el internet ya dame un dolor de cabezaCastillo de Windsor - ¿Cómo asignar instancia de nombre en la inyección de constructor

aquí está el problema:

interface IValidator 
{ 
    void Validate(object obj); 
} 

public class ValidatorA : IValidator 
{ 
    public void Validate(object obj) { } 
} 

public class ValidatorB : IValidator 
{ 
    public void Validate(object obj) { } 
} 


interface IClassA { } 
interface IClassB { } 

public class MyBaseClass 
{ 
    protected IValidator validator; 

    public void Validate() 
    { 
     validator.Validate(this); 
    } 
} 

public class ClassA : MyBaseClass, IClassA 
{ 
    //problem: validator should ValidatorA 
    public ClassA(IValidator validator) { } 
} 

public class ClassB : MyBaseClass, IClassB 
{ 
    //problem: validator should ValidatorB 
    public ClassB(IValidator validator) { } 
} 

public class OtherClass 
{ 
    public OtherClass(IClassA a, IClassB b) { } 
} 


//on Main 
var oc = container.Resolve<OtherClass>(); 

Alguna idea?

EDITAR

Me he registrado y ValidatorAValidatorB con Named, ahora el problema de cómo el castillo de Windsor puede inyectar los validador correctamente a la ClassA y ClassB, hay una manera de hacer eso? o hay alguna mejor solucion?

si alguien piensa que el diseño de mi clase es incorrecto, por favor, abro para cualquier consejo. Hasta ahora creo que es correcto. Sí, el validador tiene una configuración específica para una Clase específica. pero hay razones por las que se abstrae:

  1. El validador es un objeto complejo, en algún momento debe conectarse a la base de datos, así que DEBO pasar la interfaz en lugar de la implementación al constructor para probar la unidad.
  2. No hay manera de usar interfaz diferente para cualquiera de Validador, porque el único método que he utilizado es Validate
  3. creo MyBaseClass.Validate() una plantilla común método patrón no es así?
+2

Tu descripción del problema es abstracta. –

+2

Si ClassA requiere una implementación específica de IValidator, entonces el diseño es incorrecto, ya que la interfaz no proporciona abstracción útil. –

+0

@Jacek Grogon, no solo necesito el método 'Validate', en realidad hay una clase base de ClassA y ClassB que se llama método' Validate'. pero no lo escribo aquí solo para ocultar la complejidad. – ktutnik

Respuesta

9

Sin entrar en los detalles de su arquitectura elegida sólo se centra en la configuración del contenedor Windsor:

Si se ha registrado múltiples nombrado aplicación de una interfaz dada (IValidator), puede especificar cuál te desea utilizar al registrarse las clases de consumo (ClassA, ClassB) con el uso de ServiceOverrides:

los siguientes proveedores contenedor de configuración una OtherClass con ClassA ejemplo con una instancia ValidatorA y ClassB con un ValidatorB:

var container = new WindsorContainer(); 

container.Register(Component.For<IClassA>().ImplementedBy<ClassA>() 
    .DependsOn(ServiceOverride.ForKey<IValidator>().Eq("ValidatorA"))); 
container.Register(Component.For<IClassB>().ImplementedBy<ClassB>() 
    .DependsOn(ServiceOverride.ForKey<IValidator>().Eq("ValidatorB"))); 

container.Register(Component.For<IValidator>().ImplementedBy<ValidatorA>() 
    .Named("ValidatorA")); 
container.Register(Component.For<IValidator>().ImplementedBy<ValidatorB>() 
    .Named("ValidatorB")); 

container.Register(Component.For<OtherClass>().ImplementedBy<OtherClass>()); 

var oc = container.Resolve<OtherClass>(); 
+0

gracias, esto es lo que quiero. caso cerrado – ktutnik

1

Parece que usted está tratando de poner parejas apretadas (ClassA con ValidatorA, ClassB con ValidatorB) como los tipos independientes en un recipiente común. Esto es inutil. Si debe confiar en un acoplamiento ajustado como este, olvide la inyección de dependencia en este aspecto y simplemente haga una referencia de los tipos.

Esto tendría más sentido si pudiera implementar un validador común para todas las clases. Por ejemplo, haga que las clases sean responsables de proporcionar reglas de validación, y deje que Validator haga cumplir las reglas. O tal vez simplemente incluya toda la validación dentro de sus clases, que probablemente sea el escenario más sensato aquí.

MyBaseClass.Validate() parecen inversión de control, pero no como un método de plantilla.

+0

gracias por la respuesta, sí, la clase fue pareja, pero el proceso es repetitivo, en realidad hay tareas en 'MyBaseClass.Validate()': 1. Obtenga los errores de 'validator.Validate (this)', 2. Despacho el 'DataErrorEvent' 3. Cambie la propiedad' HasError', (Es por eso que lo llamo método tempalte) todas esas tareas deberían hacerse en modo asíncrono. sería una mala idea hacerlo en todos los ClassA y ClassB ¿verdad? – ktutnik

+0

Si es así, entonces '' Validate() '' es de hecho el método de la plantilla. Aún así, ¿por qué no poner el método de ingredientes, decir '' ValidateCore() '' en '' ClassA'' y no en '' ValidatorA''? Si es repetitivo, póngalo en '' MyBaseClass''. La extracción de la clase '' Validator'' agrega más complejidad e impide la claridad. –

+0

si no estoy msitaken, quiere decir instanciar el 'ValidatorA' dentro de' ClassA' y hacer un nuevo método 'ValidateCore' luego llamar' ValidateCore' desde 'MyBaseClass.Validate()' right ?. Creo que no puedo hacer eso porque será imposible hacer una prueba unitaria donde 'ValidatorA' o' ValidatorB' en cualquier caso deberían conectarse a la base de datos. – ktutnik

Cuestiones relacionadas