Dependency Injection Polymorphism Using Windsor Lock

How to configure an interface that has several specific implementations using Castle Windsor (using code). The following is sample code.

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 implementation:

 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; } } 

I want an instance of a particular class based on the applicability of a service tax. If a service tax is applicable, I need a ServiceTaxCalculator else DefaultCostCalculator .

How to customize this script with Castle Windsor.

+4
source share
3 answers

Since we really don’t know how you need to determine if the service tax is applicable, I like to add another solution for Mark nice answer. Here I use a decorator pattern:

 // 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. } } 

Now you can register this decorator:

 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>()) ) ); 
+3
source

Here is one way to do this:

 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>()); 

Note that the variable isServiceTaxApplicable in this example is an external variable (not shown), but you can easily replace it with another logical check.

Also note that DefaultCostCalculator translates registration into the ICostCalculcator interface. However, since this is not the first registration of this interface, this is not the default registration.

It is important to register the DefaultCostCalculator after the factory method, because it allows the Decorator pattern in cases where ServiceTaxCalculator is selected.

+3
source

Adding an answer to demonstrate @Kryzsttof's preferences for overriding services. Instead of the factory method:

 container.Register(Component.For<ICostCalculator>() .UsingFactoryMethod(k => new ServiceTaxApplicableCostCalculator( k.Resolve<ServiceTaxCalculator>(), k.Resolve<DefaultCostCalculator>()) ) ); 

Instead, you define the dependencies through DependsOn :

 container.Register(Component.For<ICostCalculator>() .ImplementedBy<ServiceTaxApplicableCostCalculator>() .DependsOn(Dependency.OnComponent("with", typeof(ServiceTaxCalculator))) .DependsOn(Dependency.OnComponent("without", typeof(DefaultCostCalculator)))); 

The only advantage that is obvious to me is that if another service is added to the ServiceTaxApplicableCostCalculator constructor, then if the service is redefined, it will work without any changes (automatically allowing the new service), while the factory method will require another call to Resolve . Other than that, this is certainly more idiomatic than using the factory method to explicitly create an object.

Further information is available in the documentation .

+2
source

Source: https://habr.com/ru/post/1344761/


All Articles