如何使用Castle Windsor(使用代码)配置具有多个具体实现的接口。以下是示例代码。
public interface ICostCalculator
{
double CalculateTotal(Order order);
}
public class DefaultCostCalculator : ICostCalculator
{
public double CalculateTotal(Order order)
{
return
order.Items.Sum(x => x.Product.Rate * x.Quantity);
}
}
ServiceTaxCalculator
实施:
public class ServiceTaxCalculator : ICostCalculator
{
private readonly ICostCalculator calculator;
private double serviveTaxRate = 10.2;
public ServiceTaxCalculator(ICostCalculator calculator)
{
this.calculator = calculator;
}
public double ServiceTaxRate
{
get { return this.serviceTaxRate; }
set { this.serviceTaxRate = value; }
}
public double CalculateTotal(Order order)
{
double innerTotal =
this.calculator.CalculateTotal(order);
innerTotal += innerTotal * servieTaxRate / 100;
return innerTotal;
}
}
我想要一个基于服务税适用性的具体类的实例。如果服务税适用,我需要ServiceTaxCalculator
其他DefaultCostCalculator
。
如何使用Castle Windsor配置此方案。
答案 0 :(得分:3)
这是一种方法:
container.Register(Component
.For<ICostCalculator>()
.UsingFactoryMethod(k =>
isServiceTaxApplicable ?
(ICostCalculator)k.Resolve<ServiceTaxCalculator>() :
k.Resolve<DefaultCostCalculator>()));
container.Register(Component.For<DefaultCostCalculator, ICostCalculator>());
container.Register(Component.For<ServiceTaxCalculator>());
请注意,此示例中的isServiceTaxApplicable
变量是外部变量(未显示),但您可以使用其他布尔检查轻松替换它。
另请注意,DefaultCostCalculator将注册转发到ICostCalculcator接口。但是,由于这不是该界面的首次注册,因此它不是默认注册。
在工厂方法之后注册DefaultCostCalculator 非常重要,因为这样可以在选择ServiceTaxCalculator的情况下启用Decorator模式。
答案 1 :(得分:3)
由于我们不知道您需要如何确定服务税是否适用,我想为Mark的好答案添加另一个解决方案。这里我使用装饰器模式:
// Decorator
public class ServiceTaxApplicableCostCalculator
: ICostCalculator
{
private readonly ICostCalculator with;
private readonly ICostCalculator without
ServiceTaxApplicableCostCalculator(
ICostCalculator with, ICostCalculator without)
{
this.with = with;
this.without = without;
}
public double CalculateTotal(Order order)
{
bool withTax = this.IsWithTax(order);
var calculator = withTax ? this.with : this.without;
return calculator.CalculateTotal(order);
}
private bool IsWithTax(Order order)
{
// determine if the order is with or without tax.
// Perhaps by using a config setting or by querying
// the database.
}
}
现在你可以注册这个装饰:
container.Register(Component.For<ServiceTaxCalculator>());
container.Register(
Component.For<DefaultCostCalculator, ICostCalculator>());
container.Register(Component.For<ICostCalculator>()
.UsingFactoryMethod(k =>
new ServiceTaxApplicableCostCalculator(
k.Resolve<ServiceTaxCalculator>(),
k.Resolve<DefaultCostCalculator>())
)
);
答案 2 :(得分:2)
添加答案以证明@ Kryzsztof对服务覆盖的偏好。而不是工厂方法:
container.Register(Component.For<ICostCalculator>()
.UsingFactoryMethod(k =>
new ServiceTaxApplicableCostCalculator(
k.Resolve<ServiceTaxCalculator>(),
k.Resolve<DefaultCostCalculator>())
)
);
您可以通过DependsOn
指定依赖项:
container.Register(Component.For<ICostCalculator>()
.ImplementedBy<ServiceTaxApplicableCostCalculator>()
.DependsOn(Dependency.OnComponent("with", typeof(ServiceTaxCalculator)))
.DependsOn(Dependency.OnComponent("without", typeof(DefaultCostCalculator))));
对我来说唯一明显的好处是,如果向ServiceTaxApplicableCostCalculator
的构造函数添加了不同的服务,则服务覆盖情况将继续工作而不进行任何更改(自动解析新服务),而工厂方法需要再次调用Resolve
。除此之外,它肯定比使用工厂方法显式创建对象更具惯用性。
documentation中提供了更多信息。