SOLID – The Dependency Inversion Principle

Definition:

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.

low level classes: are those which implement basic and primary operations.

high level classes: are those which encapsulate complex logic and rely on the low level classes.

dependency_inversion_principle

The Dependency Inversion principle (DIP) helps to loosely couple your code by ensuring that your high-level modules depend on abstractions rather than concrete implementations of lower-level modules.

The Dependency Injection pattern is an application/ implementation of this principle.

Example:

suppose that we have a banking system software. As a part of that software it is necessary to transfer money between accounts. So there is a bank account class which contains 2 properties account number and the balance. also 2 methods addFunds and removeFunds.
So to control the transfers between the accounts we have made a higher level class called trasnferManager which have properties for the two accounts involved in the transaction and for the value of the transfer.

public class BankAccount
{
   public string AccountNumber { get; set; }

   public decimal Balance { get; set; }

   public void AddFunds(decimal value)
   {
     Balance += value;
   }

   public void RemoveFunds(decimal value)
   {
     Balance -= value;
   }
}

public class TransferManager
{
   public BankAccount Source { get; set; }

   public BankAccount Destination { get; set; }

   public decimal Value { get; set; }

   public void Transfer()
   {
     Source.RemoveFunds(Value);
     Destination.AddFunds(Value);
   }
}

problem:

The problem here is that the high level TransferManager class is directly dependent upon the lower level BankAccount class. The Source and Destination properties reference the BankAccount type. This makes it impossible to substitute other account types unless they are subclasses of BankAccount. If we later want to add the ability to transfer money from a bank account to pay bills, the BillAccount class would have to inherit from BankAccount. As bills would not support the removal of funds, this is likely to break the rules of the Liskov Substitution Principle (LSP) or require changes to the TransferManager class that do not comply with the Open / Closed Principle (OCP).

solution:

Applying the DIP will solve these problems by removing direct dependencies between classes. Instead, higher level classes refer to their dependencies using abstractions, such as interfaces or abstract classes. The lower level classes will implement the interfaces, or inherit from the abstract classes. This will allow new dependencies to be substituted without effecting the code.

So lets refactor the code to be in this way :

public interface ITransferSource
{
   void RemoveFunds(decimal value);
}

public interface ITransferDestination
{
   void AddFunds(decimal value);
}

public class BankAccount : ITransferSource, ITransferDestination
{
   public string AccountNumber { get; set; }

   public decimal Balance { get; set; }

   public void AddFunds(decimal value)
   {
     Balance += value;
   }

   public void RemoveFunds(decimal value)
   {
     Balance -= value;
   }
}

public class TransferManager
{
   public ITransferSource Source { get; set; }

   public ITransferDestination Destination { get; set; }

   public decimal Value { get; set; }

   public void Transfer()
   {
     Source.RemoveFunds(Value);
     Destination.AddFunds(Value);
   }
}

This solution will increases the robustness of the software and improves flexibility. The separation of high level classes from their dependencies raises the possibility of reuse of these larger areas of functionality. Without the DIP, only the lowest level classes may be easily reusable.

Related Posts:
Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s