Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Polymorphism with Dependency Injection using Castle Windsor

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.

like image 784
Nirajan Singh Avatar asked Mar 22 '11 12:03

Nirajan Singh


People also ask

What is Castle Windsor dependency injection?

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 use polymorphism?

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.

What is dependency injection C# with example?

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.

How to implement Castle Windsor dependency injection in MVC?

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.

What is dependency injection in IOC?

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.

How do I implement castlewinsdor?

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".

What is the latest version of Castle Windsor?

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.


2 Answers

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.

like image 141
Mark Seemann Avatar answered Sep 26 '22 17:09

Mark Seemann


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>())
    )
);
like image 42
Steven Avatar answered Sep 24 '22 17:09

Steven