Castle Windsor - Cómo mapear una instancia con nombre en la inyección del constructor

tal vez esto sea facil, pero buscarlo en internet ya me da dolor de cabeza

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

estoy registrado ValidatorA y ValidatorB con Named, ahora el problema de cómo Castle Windsor puede inyectar esos validadores correctamente al ClassA y ClassB, ¿Hay una manera de hacer eso? o hay alguna solución mejor?

si hay alguien que piensa que el diseño de mi clase está mal, 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 debería conectarse a la base de datos, por lo que DEBO pasar la interfaz en lugar de la implementación al constructor por razones de prueba unitaria.
  2. No hay forma de usar una interfaz diferente para cualquiera de Validator, porque el único método que usé es Validate
  3. Creo que el MyBaseClass.Validate() una común método de plantilla patrón no?

preguntado el 04 de julio de 12 a las 09:07

Su descripción del problema es abstraer. -

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

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

actualicé el código, por lo que lo único que realmente necesito es el Validate método -

Cree una interfaz para ClassA y ClassB algo así como IClassAValidator que hereda de IValidator y no agrega nada más. Luego obtenga los validadores para implementar la interfaz específica. A ClassA se le puede inyectar IClassAValidator y pasar IValidator a MyBaseClass. -

2 Respuestas

Sin entrar en los detalles de la arquitectura elegida, solo centrándose en la configuración del contenedor Windsor:

Si ha registrado varias implementaciones con nombre en una interfaz dada (IValidator), puede especificar cuál desea usar al registrar las clases de consumidor (ClassA, ClassB) con el uso ServiceOverrides:

Los siguientes proveedores de configuración de contenedores un OtherClass con ClassA instancia con un ValidatorA y ClassB instancia 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>();

Respondido 04 Jul 12, 16:07

Parece que estás tratando de poner parejas apretadas (ClassA con ValidatorA, ClassB con ValidatorB) como tipos independientes en un contenedor común. Esto es inutil. Si debe confiar en un acoplamiento estrecho como este, olvídese de la inyección de dependencias en este sentido y simplemente haga referencia directa a 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 simplemente hacer cumplir las reglas. O tal vez solo incluya la validación completa dentro de sus clases, que es probablemente el escenario más sensato aquí.

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

Respondido 04 Jul 12, 13:07

gracias por la respuesta, sí, la clase estuvo muy apretada, pero el proceso es repetitivo, en realidad hay tareas en MyBaseClass.Validate(): 1. Obtener los errores de validator.Validate(this), 2. Enviar el DataErrorEvent 3. Cambiar el HasError propiedad, (Es por eso que lo llamo método tempalte) todas esas tareas deben realizarse de manera asíncrona. sería una mala idea hacerlo en cada ClassA y ClassB, ¿verdad? - ktutnik

Si es así, entonces Validate() es de hecho método de plantilla. Aún así, ¿por qué no poner el método del ingrediente, digamos ValidateCore() in ClassA y no en ValidatorA? Si es repetitivo, entonces póngalo en MyBaseClass. Extrayendo el Validator La clase agrega más complejidad y dificulta la claridad. - Jacek Gorgon

si no estoy equivocado, te refieres a instanciar el ValidatorA dentro ClassA y hacer un nuevo método ValidateCore luego llame ValidateCore en MyBaseClass.Validate() ¿Correcto?. creo que no puedo hacer eso porque será imposible hacer una prueba unitaria donde ValidatorA or ValidatorB en cualquier caso debe conectarse a la base de datos. - ktutnik

Me refiero a eliminar Validator* y poner esa lógica en Class*.ValidateCore() y llamarlo en MyBaseClass.Validate(). ¿Qué es exactamente lo que estás probando unitariamente? ¿Por qué ValidatorA se conecta a una base de datos? Dar más contexto. - Jacek Gorgon

ClassA o ClassB solo deben contener la lógica de la vista (estado del botón, índice seleccionado del cuadro combinado, etc.) realmente se requiere probar su lógica fuera de la llamada a la base de datos, en algunos casos, el validador se conecta a la base de datos para obtener información, ¿hay alguna coincidencia de propiedad específica? condición de los datos o no? si elimino Validator y hago la validación dentro de él para que mi prueba de unidad se conecte a la base de datos y creo que no es una buena idea, ¿crees que usé demasiado la clase de validador? por cierto... una vez más gracias, realmente aprecio su tiempo para tratar de resolver mi problema - ktutnik

No es la respuesta que estás buscando? Examinar otras preguntas etiquetadas or haz tu propia pregunta.