Castle Windsor - Cómo mapear una instancia con nombre en la inyección del constructor
Frecuentes
Visto 7,372 equipos
11
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
e ValidatorB
Named
, ahora el problema de cómo Castle Windsor puede inyectar esos validadores correctamente al ClassA
e 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:
- 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.
- No hay forma de usar una interfaz diferente para cualquiera de Validator, porque el único método que usé es
Validate
- Creo que el
MyBaseClass.Validate()
una común método de plantilla patrón no?
2 Respuestas
12
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
ClassA
instancia con un ValidatorA
e 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
2
Parece que estás tratando de poner parejas apretadas (ClassA
ValidatorA
, ClassB
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
del 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 c# castle-windsor or haz tu propia pregunta.
Su descripción del problema es abstraer. - Damian Leszczyński - Vash
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 Gorgoń
@Jacek Grogon, no, solo necesito el
Validate
método, en realidad hay una clase base de ClassA y ClassB que se llama elValidate
método. pero no lo escribo aquí solo para ocultar la complejidad. - ktutnikactualicé el código, por lo que lo único que realmente necesito es el
Validate
método - ktutnikCree 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. - Jack Hughes