问题描述
我的Web应用程序在业务逻辑和presentation逻辑一些轻微的变化取决于用户所登录的类型。这似乎是通过基于用户类型注入不同的具体类获得的变化是一个非常适合DI。所以,我想知道什么StructureMap的功能,我应该用它来实现这一目标(或者,如果我的路要走基地DI的目的)。
(我刚刚得知,配置文件是不是为了实现这一点,因为设置配置文件是不是每个线程的操作方式:http://stackoverflow.com/questions/1494937/are-structuremap-profiles-thread-safe)
修改
这是一段路要走这个?
公共类的HomeController
{
私人ISomeDependancy _someDependancy;
公共HomeController的(ISomeDependancy someDependancy)
{
_someDependancy = someDependancy;
}
公共字符串GetNameFromDependancy()
{
返回_someDependancy.GetName();
}
}
公共接口ISomeDependancy
{
字符串的GetName();
}
公共类VersionASomeDependancy:ISomeDependancy
{
公共字符串的GetName()
{
回到我的名字是版本A;
}
}
公共类VersionBSomeDependancy:ISomeDependancy
{
公共字符串的GetName()
{
回到我的名字是版本B;
}
}
公共类VersionARegistry:注册表
{
公共VersionARegistry()
{
//这里建立复杂的图形
ForRequestedType&其中; ISomeDependancy>()&TheDefaultIsConcreteType所述; VersionASomeDependancy>();
}
}
公共类VersionBRegistry:注册表
{
公共VersionBRegistry()
{
//这里建立复杂的图形
ForRequestedType&其中; ISomeDependancy>()&TheDefaultIsConcreteType所述; VersionBSomeDependancy>();
}
}
公共类ContainerA:集装箱
{
公共ContainerA()
:基座(新VersionARegistry())
{
}
}
公共类ContainerB:集装箱
{
公共ContainerB()
:基座(新VersionBRegistry())
{
}
}
[的TestFixture]
公共类线束
{
[测试]
公共无效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的控制器;
的IContainer containerForVersionA = ObjectFactory.GetNamedInstance&其中;的IContainer&GT(VersionA);
控制器= containerForVersionA.GetInstance< HomeController的>();
Assert.That(controller.GetNameFromDependancy(),Is.EqualTo(我的名字是版本A));
的IContainer containerForVersionB = ObjectFactory.GetNamedInstance&其中;的IContainer&GT(VersionB);
控制器= containerForVersionB.GetInstance< HomeController的>();
Assert.That(controller.GetNameFromDependancy(),Is.EqualTo(我的名字叫B版));
}
}
实现,这是马克描述的一种常见方式。你有一个类,它的所有具体实例的数组(它的必须的是一个数组StructureMap表现如预期),然后使用一些逻辑,找出要使用的实例。
有些样品code,你可以粘贴到一个控制台程序或单元测试:
VAR集装箱=新容器(X => x.Scan(扫描=>
{
scan.TheCallingAssembly();
scan.WithDefaultConventions();
scan.AddAllTypesOf&其中; IDiscountCalculator>();
}));
VAR策略= container.GetInstance< IDiscountStrategy>();
Console.WriteLine(strategy.GetDiscount(常规,10)); // 0
Console.WriteLine(strategy.GetDiscount(正常,10)); // 1
Console.WriteLine(strategy.GetDiscount(特殊,10)); // 5
取决于以下类型:
公共接口IDiscountStrategy
{
十进制GetDiscount(字符串的用户类型,小数的OrderTotal);
}
公共类DiscountStrategy:IDiscountStrategy
{
私人只读IDiscountCalculator [] _discountCalculators;
公共DiscountStrategy(IDiscountCalculator [] discountCalculators)
{
_discountCalculators = discountCalculators;
}
公共十进制GetDiscount(字符串的用户类型,小数的OrderTotal)
{
VAR计算器= _discountCalculators.FirstOrDefault(X => x.AppliesTo(用户类型));
如果(计算器== NULL)返回0;
返回calculator.CalculateDiscount(的OrderTotal);
}
}
公共接口IDiscountCalculator
{
布尔AppliesTo(字符串的用户类型);
十进制CalculateDiscount(十进制的OrderTotal);
}
公共类NormalUserDiscountCalculator:IDiscountCalculator
{
公共BOOL AppliesTo(字符串的用户类型)
{
返回的用户类型==正常;
}
公共小数CalculateDiscount(十进制的OrderTotal)
{
返回的OrderTotal *0.1米;
}
}
公共类SpecialUserDiscountCalculator:IDiscountCalculator
{
公共BOOL AppliesTo(字符串的用户类型)
{
返回的用户类型==特别;
}
公共小数CalculateDiscount(十进制的OrderTotal)
{
返回的OrderTotal *0.5米;
}
}
My web app has some slight variations in business logic and presentation logic depending on the type of user that is logged in. It seems like getting variations by injecting different concrete classes based on the user type is a good fit for DI. So I'm wondering what features of StructureMap I should use to achieve this (or if I'm way off base on the purposes of DI).
(I just learned that Profiles are not the way to accomplish this because setting the Profile isn't a per-thread operation: http://stackoverflow.com/questions/1494937/are-structuremap-profiles-thread-safe)
EDIT
Is this the way to go about this?
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"));
}
}
One common way to implement this is as Mark described. You have a class that takes in an array of all concrete instances (it must be an array for StructureMap to behave as expected), and then uses some logic to figure out which instance to use.
Some sample code you can paste into a console program or unit test:
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
which depends on the following 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;
}
}
这篇关于最好的方式来使用StructureMap实施战略格局的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!