Sunday, April 20, 2008

Dependency Inversion Principle

The principle states: a. High level modules should not depend upon low level modules. Both should depend upon abstractions . b. Abstractions should not depend upon details. Details should depend upon abstractions.

I used the exact same code examples as I used for my Open Closed Principle because these two principles are very closely related. I'll just provide different reasoning for the changes. Below is an example of some code breaking this principle:

Class: WeatherDisplay
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
namespace DIP
{
    public class WeatherDisplay
    {
        private readonly ProvideTemperature _ProvideTemperature;
        private readonly ProvideWindSpeed _ProvideWindSpeed;

        public WeatherDisplay(int temperature, int windSpeed)
        {
            _ProvideTemperature = new ProvideTemperature(temperature);
            _ProvideWindSpeed = new ProvideWindSpeed(windSpeed);
        }

        public void DisplayWeather()
        {
            Console.WriteLine(_ProvideTemperature.Temperature());
            Console.WriteLine(_ProvideWindSpeed.WindSpeed());
        }
    }
}
Class: ProvideTemperature
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
namespace DIP
{
    public class ProvideTemperature
    {
        private readonly int _Temperature;

        public ProvideTemperature(int temperature)
        {
            _Temperature = temperature;
        }

        public string Temperature()
        {
            return("The current temperature is: " + _Temperature + " degrees celcius.");
        }
    }
}
Class: ProvideWindSpeed
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
namespace DIP
{
    public class ProvideWindSpeed
    {
        private readonly int _WindSpeed;

        public ProvideWindSpeed(int windSpeed)
        {
            _WindSpeed = windSpeed;
        }

        public string WindSpeed()
        {
            return("The current wind speed is: " + _WindSpeed + " meters per second.");
        }
    }
}
As you can see there are two classes being referenced inside the class WeatherDisplay this means that the class WeatherDisplay depends on the two classes ProvideTemperature and ProvideWindSpeed. If either of these classes needs to change or if another implementation should be added than the class WeatherDisplay is affected.

Below you can see a solution that would obey the Dependency Inversion Principle:
Class: WeatherDisplay
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
namespace DIP
{
    public class WeatherDisplay
    {
        private readonly ITemperatureProvider _TemperatureProvider;
        private readonly IWindSpeedProvider _WindSpeedProvider;

        public WeatherDisplay(ITemperatureProvider temperatureProvider, IWindSpeedProvider windSpeedProvider)
        {
            _TemperatureProvider = temperatureProvider;
            _WindSpeedProvider = windSpeedProvider;
        }

        public void DisplayWeather()
        {
            Console.WriteLine(_TemperatureProvider.Temperature());
            Console.WriteLine(_WindSpeedProvider.WindSpeed());
        }
    }
}
Interface: ITemperatureProvider
1
2
3
4
5
6
7
namespace DIP
{
    public interface ITemperatureProvider
    {
        string Temperature();
    }
}
Interface: IWindSpeedProvider
1
2
3
4
5
6
7
namespace DIP
{
    public interface IWindSpeedProvider
    {
        string WindSpeed();
    }
}
When we implement the WeatherDisplay class in this way we factor out any direct dependencies with the classes ProvideTemperature and ProvideWindSpeed. We could provide any implementation of the ITemperatureProvider and IWindSpeedProvider without the need to make any modifications to the class. For example:
Class: ProvideTemperatureInCelcius : ITemperatureProvider
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
namespace DIP
{
    public class ProvideTemperatureInCelcius : ITemperatureProvider
    {
        private readonly int _Temperature;

        public ProvideTemperatureInCelcius(int temperature)
        {
            _Temperature = temperature;
        }

        public string Temperature()
        {
            return("The current temperature is: " + _Temperature + " degrees celcius.");
        }
    }
}
Class: ProvideTemperatureInFahrenheit : ITemperatureProvider
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
namespace DIP
{
    public class ProvideTemperatureInFahrenheit : ITemperatureProvider
    {
        private readonly int _Temperature;

        public ProvideTemperatureInFahrenheit(int temperature)
        {
            _Temperature = temperature;
        }

        public string Temperature()
        {
            double fahrenheit = (212 - 32) / 100 * _Temperature + 32;
            return ("The current temperature is: " + fahrenheit + " degrees fahrenheit.");
        }
    }
}
I hope you found these examples helpful. Also take a look at the following links and my next post DIP – Dependency Inversion Principle using Spring.Net:

http://www.objectmentor.com/resources/articles/dip.pdf
http://www.lostechies.com/blogs/jimmy_bogard/archive/2008/03/31/ptom-the-dependency-inversion-principle.aspx
http://butunclebob.com/ArticleS.UncleBob.PrinciplesOfOod

1 comment:

Anonymous said...

Please keep on posting informative snippets as now..