How to configure Interface having multiple concrete implementation using Castle Windsor (using code). Below is the 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);
}
}
The 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 the instance of a concrete class based on service tax applicability. If service tax is applicable, I need ServiceTaxCalculator
else DefaultCostCalculator
.
How to configure this scenario using Castle Windsor.
Castle Windsor is Dependency Injection container. It means with the help of this you can inject your dependencies and use them without creating them with the help of new keyword.
Does dependency injection qualify as polymorphism? DI essentially defines a set of interface parameters which can be satisfied by any classes implementing those parameters. So this seems to qualify as polymorphism.
Using dependency injection, we can pass an instance of class C to class B, and pass an instance of B to class A, instead of having these classes to construct the instances of B and C. In the example, below, class Runner has a dependency on the class Logger.
This blog will explain how to implement Castle Windsor Dependency injection in MVC. Go to Project, right-click on "References", select "Manage NuGet Packages" Search for "Castle.Windsor" in the search bar. Install it. Go to App_Start folder. Create a class called "ContainerBootstrapper". It should be like below.
This automated dependency injection is one of the most valuable features offered by Castle Windsor and other IoC frameworks. Dependency Injection and Inversion of Control are powerful tools available to modern software engineers.
Steps to implement CastleWinsdor Go to Project, right-click on "References", select "Manage NuGet Packages" Search for "Castle.Windsor" in the search bar. Install it. Go to App_Start folder. Create a class called "ContainerBootstrapper".
Castle Windsor is a best of breed, mature Inversion of Control container available for .NET and Silverlight. The current version is 5.0, released in February 2019. Refer to the links on the right to download it from GitHub or NuGet.
Here's one way to do it:
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>());
Notice that the isServiceTaxApplicable
variable in this example is an outer variable (not shown), but you can easily replace it with some other boolean check.
Also notice that the DefaultCostCalculator forwards the registration to the ICostCalculcator interface. However, since this is not the first registration of that interface, it's not the default registration.
It's important to register the DefaultCostCalculator after the factory method because this enables the Decorator pattern in those cases where the ServiceTaxCalculator is chosen.
Since we don't really know how you need to determine whether the service tax is applicable, I like to add another solution to Mark's nice answer. Here I use the 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>())
)
);
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With