The SOLID Principles in C# – Dependency Inversion

The last post in the SOLID by Example series deals with the Dependency Inversion Principle (DIP). It states that high-level classes should not depend on low-level classes. Both should depend on abstractions. Abstractions should not depend on details. Details should depend on abstractions.

For us developers S.O.L.I.D. is a five letter acronym with each letter pointing to a basic principle of good Object Oriented Design. The principle set was introduced almost twenty years ago by Robert C. Martin (Uncle Bob), a well known author, speaker and thinker on the subject. In this series we discuss each principle with some practical code examples.

By dependencies we mean all lower-level modules, used by our code, that are likely to change. For instance files and the filesystem, databases and datasets, third party libraries and components, webservices, configuration, system resources, logging… and so on. One could even argue that the .Net Framework is a lower-level dependency.

In the traditional N-tier layering structure, where we have maybe a GUI, Business Layer and Data Access Layer, we see higher level modules instantiate and call lower-level modules. This is creating a dependency from the high-level GUI through the BLL to the lower-level DAL. These dependencies make it much harder for us to change, maintain and test the system.

In this example we have a BirthdayCalculator class which has a list of birthdays and a GetTodaysBirthdays() method to retrieve todays birthday list.

Dependency Inversion Birthday Calculator V2

We new up the birthday list inside of the BirthdayCalculator constructor.

public class BirthdayCalculator
{
    private readonly List<Birthday> _birthdays;
 
    public BirthdayCalculator()
    {
        _birthdays = new List<Birthday>();
    }
 
    public List<Birthday> Birthdays
    {
        get { return _birthdays; }
    }
 
    public List<Birthday> GetTodaysBirthdays()
    {
        // Update: 2012-08-07
        // Made an enormous booboo on this piece of code before
        // Solved thanks to Dejan
        return _birthdays
            .Where(bd => bd.Date.Month == DateTime.Now.Date.Month)
            .Where(bd => bd.Date.Day == DateTime.Now.Date.Day)
            .ToList();
    }
}

The birthday list is what we call a hidden dependency. If we create an instance of the BirthdayCalculator we don’t know it has a dependency on the list of birthdays (a lower-level class). Another hidden dependency is the explicit call to the static property DateTime.Now to query for the current system time.

Let’s inverse these dependencies. We do this by placing a small interface between our modules and let them depend upon these abstractions. In this case the IList of type Birthday. We new it up outside of the BirthdayCalculator, injecting it into the object via the constructor (dependency injection). The class design now looks something like this:

public class BirthdayCalculator
{
    private readonly IList<Birthday> _birthdays;
 
    public BirthdayCalculator(IList<Birthday> birthdays)
    {
        _birthdays = birthdays;
    }
 
    public IList<Birthday> Birthdays
    {
        get { return _birthdays; }
    }
 
    public IList<Birthday> GetBirthdays(DateTime checkDate)
    {
        return _birthdays
            .Where(bd => bd.Date.Day == checkDate.Day)
            .Where(bd => bd.Date.Month == checkDate.Month)
            .ToList();
    }
}

What we have here is an independent class with a constructor clearly stating the dependency it needs to function. The DateTime.Now is gone. The CheckDate is provided whenever the GetBirthdays method is called. We can now change and test this class much easier, because the control of the dependencies lay outside of the class.

The SOLID Principles in C# – Interface Segregation

The fourth post in the SOLID by Example series deals with the Interface Segregation Principle (ISP). It states that clients should not be forced to implement interfaces they don’t use. Or as Uncle Bob puts it: Make fine grained interfaces that are client specific.

For us developers S.O.L.I.D. is a five letter acronym with each letter pointing to a basic principle of good Object Oriented Design. The principle set was introduced almost twenty years ago by Robert C. Martin (Uncle Bob), a well known author, speaker and thinker on the subject. In this series we discuss each principle with some practical code examples.

In the following example we have a simple Person class with some obvious person-like methods and properties. We also have a BirthdayCalendar class that has an Add() method to add a person’s birthday to the calendar. The Add() method takes a Person object as a parameter.

Interface Segregation Person Fat Diagram

This makes sure that Person and BirtdayCalendar are tightly coupled. If Person changes, this can have an impact. If we want to add birtdays from entities other than from a Person we’re in trouble. There’s also no need for BirtdayCalendar to know all of Persons interface.

This is why some might say that this class has a fat interface. It has a few useless properties and methods for different clients using the interface. To prevent this we let BirthdayCalendar specify an interface that Person must implement. In this case IBirthday with a Name, Age and DayOfBirth property.

Interface Segregation Person Lean Diagram

This makes BirthdayCalendar independent of the Person class which makes it easier to maintain and extend. Imagine we also wanted to add the birthdays of pets to the BirthdayCalendar. The Pet class only had to implement the IBirtday interface to achieve that.

The SOLID Principles in C# – Liskov Substitution

The third post in the SOLID by Example series deals with the Liskov Substitution Principle (LSP). It states that derived classes must be substitutable for their base classes. The principle was first mentioned by Barbara Liskov in the late eighties.

For us developers S.O.L.I.D. is a five letter acronym with each letter pointing to a basic principle of good Object Oriented Design. The principle set was introduced almost twenty years ago by Robert C. Martin (Uncle Bob), a well known author, speaker and thinker on the subject. In this series we discuss each principle with some practical code examples.

Most developers embrace the Liskov Substitution Principle without even knowing it. It’s quite obvious. If you take a look at the examples that break the principle, you’ll most likely find them to be a little odd. A common example is that of a rectangle and it’s derived class; square. Now a square is-a kind of rectangle, but can a rectangle be a substitution for a square?

Liskov Substitution Rectangle Square Diagram

namespace LiskovSubstitutionPrinciple
{
    public class Rectangle
    {
        public virtual int Width { get; set; }
        public virtual int Height { get; set; }
    }
 
    public class Square : Rectangle
    {
        public override int Height
        {
            get { return base.Height; }
            set { SetWidthAndHeight(value); }
        }
 
        public override int Width
        {
            get { return base.Width; }
            set { SetWidthAndHeight(value); }
        }
 
        // Both sides of a square are equal.
        private void SetWidthAndHeight(int value)
        {
            base.Height = value;
            base.Width = value;
        }
    }
}

The Liskov Substitution Principle is broken here, because the behavior of the Width and Height properties changed in the descendant class. Substitution of the Square with a Rectangle gives some unexpected results.

using System;
 
namespace LiskovSubstitutionPrinciple
{
    internal class Program
    {
        private static void Main()
        {
            Rectangle rectangle = new Square();
            rectangle.Width = 3;
            rectangle.Height = 2;
 
            Console.WriteLine("{0} x {1}",
                              rectangle.Width,
                              rectangle.Height);
 
            Console.ReadLine();
        }
    }
}

Liskov Substitution Rectangle Square Console

The Width of the substituted ‘Rectangle’ is 2 and not the given 3. Since the behavior setting the Square property is different from the Rectangle, we can’t substitute the Square for a Rectangle. A better design, following the Liskov Substitution Principle, has a base class Shape for both the Rectangle and Square descendant classes.

Liskov Substitution Shape Rectangle Square Diagram

The Liskov Substitution Principle held here, because the behavior of the Width and Height properties were not changed in the descendant class. Substitution of the Square or Rectangle with the Shape class gives the expected result.

using System;
 
namespace LiskovSubstitutionPrinciple
{
    internal class Program
    {
        private static void Main()
        {
            Shape rectangle = new Rectangle();
            rectangle.Width = 3;
            rectangle.Height = 2;
 
            Shape square = new Square();
            square.Width = 3;
            square.Height = 2;
            
            Console.WriteLine("Rectangle {0} x {1}",
                              rectangle.Width,
                              rectangle.Height);
 
            Console.WriteLine("Square {0} x {1}",
                              square.Width,
                              square.Height);
 
            Console.ReadLine();
        }
    }
}

Liskov Substitution Shape Rectangle Square Console

The SOLID Principles in C# – Open / Closed

The second post in the SOLID by Example series deals with the Open / Closed Principle (OCP). This is the notion that an object should be open for extension, but closed for modification.

For us developers S.O.L.I.D. is a five letter acronym with each letter pointing to a basic principle of good Object Oriented Design. The principle set was introduced almost twenty years ago by Robert C. Martin (Uncle Bob), a well known author, speaker and thinker on the subject. In this series we discuss each principle with some practical code examples.

In the example below we have a shopping cart with a graduated discount calculation. If we buy more than five products we get a 10% discount on the total ammount. If we buy ten units or more we get a 15% discount. If we buy twenty units or more, we get a whooping 25% discount. We pick the highest percentage if more rules apply.

Open Closed Principle Shopping Cart Diagram

using System.Collections.Generic;
 
namespace OpenClosedPrinciple
{
    public class ShoppingCart
    {
        private List<CartItem> _items;
 
        public decimal GetDiscountPercentage()
        {
            decimal ammount = 0;
 
            // Red flag!
            if (_items.Count >= 5 && _items.Count < 10)
            {
                ammount = 10;
            }
            else if (_items.Count >= 10 && _items.Count < 15)
            {
                ammount = 15;
            }
            else if (_items.Count >= 15)
            {
                ammount = 25;
            }
 
            return ammount;
        }
 
        public void Add(CartItem product)
        {
            // Add an item
        }
 
        public void Delete(CartItem product)
        {
            // Delete an item
        }
    }
}

The implementation of the ShoppingCart class violates a number of SOLID principles, including the Single Responsibility Principle. For simplicity we keep it that way and focus solely on the Open / Closed Principle.

The GetDiscountPercentage() enforces some discount rules. Any change to the business rules in the future forces us to change the ShoppingCart class. This violates the Open / Closed Principle. A typical red flag is a switch statement, or if-else constructs with some business logic behind it. We need to design the ShoppingCart class in such a way that it is open to extension (like adding a new discount percentage) without modification. One way to establish this is by applying the Strategy Pattern.

We move the business logic of calculating the discount percentage out of the ShoppingCart class. We replace this by a DiscountCalculator solely responsible for enforcing the appropriate discount rules while returning the right percentage amount.

Open Closed Principle Discount Calculator Diagram

using System.Collections.Generic;
using System.Linq;
 
namespace OpenClosedPrinciple
{
    public class DiscountCalculator : IDiscountCalculator
    {
        private readonly List<IDiscountRule> _discountRules;
 
        public DiscountCalculator(List<IDiscountRule> discountRules)
        {
            _discountRules = discountRules;
        }
 
        #region IDiscountCalculator Members
 
        public decimal Calculate(int itemCount)
        {
            return _discountRules
                .First(dr => dr.Match(itemCount))
                .Ammount;
        }
 
        #endregion
    }
}

One discount rule would look something like this.

namespace OpenClosedPrinciple
{
    internal class DiscountRuleTenItems : IDiscountRule
    {
        #region IDiscountRule Members
 
        public decimal Ammount
        {
            get { return 15; }
        }
 
        public bool Match(int itemCount)
        {
            return itemCount >= 10 && itemCount < 15;
        }
 
        #endregion
    }
}

The ShoppingCart now calls the Calculate() method of the DiscountCalculator to get the right percentage. If we want to add another discount business rule to the set, we do not need to change the ShoppingCart nor the DiscountCalculator.

using System;
using System.Collections.Generic;
 
namespace OpenClosedPrinciple
{
    internal class Program
    {
        private static void Main()
        {
            var discountRules =
                new List<IDiscountRule>
                    {
                        new DiscountRuleNoDiscount(),
                        new DiscountRuleFiveItems(),
                        new DiscountRuleTenItems(),
                        new DiscountRuleTwentyItems(),
                    };
 
            var shoppingCart = new ShoppingCart(
                new DiscountCalculator(discountRules),
                new List<CartItem>());
 
            // Add 12 items to the cart
            for (int i = 0; i < 12; i++)
            {
                shoppingCart.Add(new CartItem());
            }
 
            Console.WriteLine("{0} items gives us a {1}% discount",
                              shoppingCart.ItemCount,
                              shoppingCart.GetDiscountPercentage());
 
            Console.ReadLine();
        }
    }
}

Open Closed Principle Shopping Cart Console

Download the Open Closed Principle Example Solution.

The SOLID Principles in C# – Single Responsibility

The first post in the SOLID by Example series deals with the Single Responsibility Principle (SRP). This is the notion that an object should have only a single responsibility. Uncle Bob defines a responsibility to be ‘a reason for change’. The more responsibilities a class has, the more change can be expected. The more expected change, the more likely is the introduction of bugs. Changes to one responsibility can have an impact on other responsibilities.

For us developers S.O.L.I.D. is a five letter acronym with each letter pointing to a basic principle of good Object Oriented Design. The principle set was introduced almost twenty years ago by Robert C. Martin (Uncle Bob), a well known author, speaker and thinker on the subject. In this series we discuss each principle with some practical code examples.

In this example we create a Radio class with some common operations. We can turn the volume up or down and change the station. Here is one way we could implement this class.

Single Responsibility Principle Radio Class

One could argue that the Radio class has two responsibilities, being volume and station management. These operations will be called from completely different areas of the client using it. Changes can occur whenever we want to modify some of the volume- or station management logic. By separating these responsibilities into distinct classes, we can avoid breakage in other parts of our class when our code meets a new requirement. The class design could end up like this:

Single Responsibility Principle Radio Managers

Now this design still does violate other SOLID principles, but it is just to make the Single Responsibility point clear. The class design greatly improves re-usability and maintainability. It’s more loosely coupled and clean. It’s also better testable. Changes to one responsibility does not have an impact on the rest of the design.