使用StructureMap来实现Strategy模式的最佳方法
我的Web应用程序在业务逻辑和表示逻辑上有一些细微的变化,具体取决于login用户的types。通过根据用户types注入不同的具体类来获得变化似乎非常适合DI。 所以我想知道我应该使用什么样的StructureMap来实现这个function(或者如果我是基于DI的目的而离开的话)。
(我刚刚了解到configuration文件不是实现这一目标的方法,因为设置configuration文件不是每个线程操作: StructureMapconfiguration文件是否线程安全? )
编辑
这是这样的吗?
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<ISomeDependancy>().TheDefaultIsConcreteType<VersionASomeDependancy>(); } } public class VersionBRegistry : Registry { public VersionBRegistry() { // build up complex graph here ForRequestedType<ISomeDependancy>().TheDefaultIsConcreteType<VersionBSomeDependancy>(); } } 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<IContainer>().AddInstances( x => { x.OfConcreteType<ContainerA>().WithName("VersionA"); x.OfConcreteType<ContainerB>().WithName("VersionB"); }).CacheBy(InstanceScope.Singleton); }); HomeController controller; IContainer containerForVersionA = ObjectFactory.GetNamedInstance<IContainer>("VersionA"); controller = containerForVersionA.GetInstance<HomeController>(); Assert.That(controller.GetNameFromDependancy(), Is.EqualTo("My Name is Version A")); IContainer containerForVersionB = ObjectFactory.GetNamedInstance<IContainer>("VersionB"); controller = containerForVersionB.GetInstance<HomeController>(); Assert.That(controller.GetNameFromDependancy(), Is.EqualTo("My Name is Version B")); } }
一个常见的方式来实现这是马克描述。 你有一个接受所有具体实例的数组的类(它必须是一个用于StructureMap的数组),然后使用一些逻辑来确定使用哪个实例。
一些示例代码可以粘贴到控制台程序或unit testing中:
var container = new Container(x => x.Scan(scan => { scan.TheCallingAssembly(); scan.WithDefaultConventions(); scan.AddAllTypesOf<IDiscountCalculator>(); })); var strategy = container.GetInstance<IDiscountStrategy>(); Console.WriteLine(strategy.GetDiscount("Regular", 10)); // 0 Console.WriteLine(strategy.GetDiscount("Normal", 10)); // 1 Console.WriteLine(strategy.GetDiscount("Special", 10)); // 5
这取决于以下types:
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; } }
我会说这不是DI的核心目的 – 即连接和注入依赖关系,无论它们是什么。 应用逻辑不应该涉及组件的接线 – 它应该严格基于configuration; 通过代码或.config文件。 该configuration是在整个应用程序范围内的,所以定义一个随用户而变的configuration是相当困难的。
也就是说,你所问的与DI完全一致 – 它本身就与DI直接相关。
为了您的特定目的,我将以接口或抽象基类的forms定义一个新的依赖关系。 这将是一个策略,根据当前用户select正确的具体types(你想改变的)。
您可以使用DI将所有可用的具体types注入到此策略中,然后基于当前用户,该策略将具有返回这些注入服务中正确select的方法或属性。
在您曾经依赖各种用户服务的地方,您可以删除那些旧的依赖关系,并将其replace为对策略的依赖关系。