La mejor forma de usar StructureMap para implementar el patrón de Estrategia

Mi aplicación web tiene algunas ligeras variaciones en lógica de negocios y lógica de presentación dependiendo del tipo de usuario que está conectado. Parece que obtener variaciones inyectando diferentes clases concretas basadas en el tipo de usuario es una buena opción para DI. Así que me pregunto qué características de StructureMap debería usar para lograr esto (o si estoy fuera de la base en los propósitos de DI).

(Acabo de enterarme de que los perfiles no son la forma de lograr esto porque configurar el perfil no es una operación por subproceso: ¿Los perfiles de StructureMap son seguros? )

EDITAR

¿Es esta la manera de hacerlo?

public class HomeController { private ISomeDependancy _someDependancy; public HomeController(ISomeDependancy someDependancy) { _someDependancy = someDependancy; } public string GetNameFromDependancy() { return _someDependancy.GetName(); } } public interface ISomeDependancy { string GetName(); } public class VersionASomeDependancy : ISomeDependancy { public string GetName() { return "My Name is Version A"; } } public class VersionBSomeDependancy : ISomeDependancy { public string GetName() { return "My Name is Version B"; } } public class VersionARegistry : Registry { public VersionARegistry() { // build up complex graph here ForRequestedType().TheDefaultIsConcreteType(); } } public class VersionBRegistry : Registry { public VersionBRegistry() { // build up complex graph here ForRequestedType().TheDefaultIsConcreteType(); } } public class ContainerA : Container { public ContainerA() : base(new VersionARegistry()) { } } public class ContainerB : Container { public ContainerB() : base(new VersionBRegistry()) { } } [TestFixture] public class Harness { [Test] public void ensure_that_versions_load_based_on_named_containers() { ObjectFactory.Initialize(c => { c.ForRequestedType().AddInstances( x => { x.OfConcreteType().WithName("VersionA"); x.OfConcreteType().WithName("VersionB"); }).CacheBy(InstanceScope.Singleton); }); HomeController controller; IContainer containerForVersionA = ObjectFactory.GetNamedInstance("VersionA"); controller = containerForVersionA.GetInstance(); Assert.That(controller.GetNameFromDependancy(), Is.EqualTo("My Name is Version A")); IContainer containerForVersionB = ObjectFactory.GetNamedInstance("VersionB"); controller = containerForVersionB.GetInstance(); Assert.That(controller.GetNameFromDependancy(), Is.EqualTo("My Name is Version B")); } } 

Una forma común de implementar esto es como describió Mark. Tiene una clase que toma una matriz de todas las instancias concretas ( debe ser una matriz para que StructureMap se comporte como se esperaba), y luego utiliza cierta lógica para descubrir qué instancia usar.

Algunos ejemplos de código que puede pegar en un progtwig de consola o prueba de unidad:

 var container = new Container(x => x.Scan(scan => { scan.TheCallingAssembly(); scan.WithDefaultConventions(); scan.AddAllTypesOf(); })); var strategy = container.GetInstance(); Console.WriteLine(strategy.GetDiscount("Regular", 10)); // 0 Console.WriteLine(strategy.GetDiscount("Normal", 10)); // 1 Console.WriteLine(strategy.GetDiscount("Special", 10)); // 5 

que depende de los siguientes tipos:

 public interface IDiscountStrategy { decimal GetDiscount(string userType, decimal orderTotal); } public class DiscountStrategy : IDiscountStrategy { private readonly IDiscountCalculator[] _discountCalculators; public DiscountStrategy(IDiscountCalculator[] discountCalculators) { _discountCalculators = discountCalculators; } public decimal GetDiscount(string userType, decimal orderTotal) { var calculator = _discountCalculators.FirstOrDefault(x => x.AppliesTo(userType)); if (calculator == null) return 0; return calculator.CalculateDiscount(orderTotal); } } public interface IDiscountCalculator { bool AppliesTo(string userType); decimal CalculateDiscount(decimal orderTotal); } public class NormalUserDiscountCalculator : IDiscountCalculator { public bool AppliesTo(string userType) { return userType == "Normal"; } public decimal CalculateDiscount(decimal orderTotal) { return orderTotal * 0.1m; } } public class SpecialUserDiscountCalculator : IDiscountCalculator { public bool AppliesTo(string userType) { return userType == "Special"; } public decimal CalculateDiscount(decimal orderTotal) { return orderTotal * 0.5m; } } 

Yo diría que este no es el propósito central de DI, es decir, conectar e inyectar dependencias, sean las que sean. No se debe involucrar ninguna lógica de aplicación en el cableado de los componentes; debe basarse estrictamente en la configuración; ya sea por código o archivo .config. Esa configuración es para toda la aplicación, por lo que es bastante difícil definir una configuración que varía según el usuario.

Dicho esto, lo que estás preguntando va de la mano con DI, es un poco perpendicular a la DI en sí misma.

Para su propósito específico, definiría una nueva dependencia en la forma de una interfaz o clase base abstracta. Esta sería una estrategia que selecciona los tipos de hormigón correctos (los que desea variar) en función del usuario actual.

Puede usar DI para inyectar todos los tipos concretos disponibles en esta estrategia, que luego tendría un método o propiedad que devuelva la elección correcta entre los servicios inyectados, según el usuario actual.

En todos los lugares donde solía depender de los servicios de cada usuario, elimina esas antiguas dependencias y las reemplaza con una dependencia de la Estrategia.