SOLID Design Principles – Dependency Inversion Principle (DIP)

 

DIP states that the higher level modules should be coupled with the lower level modules with complete abstraction. Meaning

  • The high level modules should not depend on low level modules but both should depend on abstraction.
  • Abstraction should not depend on detail but detail should depend on abstraction.

Following DIP allows our code to be loosely coupled thus ensuring that the high level modules are dependent on abstraction rather than concrete implementation of low level modules. The Dependency Injection Principle is an implementation of this principle.

 SOLID Design Principles   Dependency Inversion Principle (DIP)

In the image above it is obvious that we would never solder the wire directly to the supply but a level of abstraction by multiple plugs by simply plugging in.

Dependencies

Before about the dependency inversion principle in detail let us first understand what dependencies are and what dependencies we add into our modules without even knowing.

We add many dependencies in our code during the course of development. If we are developing a .NET application we would most probably have a dependency on the .NET framework. That is not a major concern because the framework in unlikely to change during the course of our development. However our major concern should be the dependencies that we add into our application that might change like third party libraries. Another common dependency that we have in the code is the database dependency. So we should try to make sure these dependencies are not implicit but explicit so that we can replacement implementations for these easily. The following is the list of common dependencies that we might have in our applications.

  • Framework
  • Third Party Libraries
  • Database
  • File System
  • Email
  • Web Services
  • System Resources (Clock)
  • Configuration
  • The new keyword
  • Static methods
  • Thread.Sleep
  • Random

Mostly we add dependencies into the application when the higher level modules call the lower level modules and the high level modules instantiate the lower level modules as they need them.  For example the user interface logic could depend on the business logic and business logic might instantiate the Infrastructure classes, data access classes, etc. So the user interface logic could depend on the business logic and business logic could depend on the Infrastructure or data access logic.

 

Let us have a look at some code that violates DIP. Say we have a class order that exposes the checkout method and has 2 methods: ProcessOrder() and ProcessPayment(). We can see neither there are any explicit dependencies set for the order class nor are there any implicit dependencies in the Checkout method. We could also see that neither ProcessPayment nor ProcessOrder declare any dependencies.

 

When we go and have a look at the implementations of these methods we see that the ProcessPayment method has a dependency on the PaymentGateway to charge the credit card with the amount and the ProcessOrder method has a dependency on the InventorySystem to reserve the item in the inventory.

So the problem starts when any of these systems (PaymentGateway or InventorySystem) is not available or changes. It issues with this types of implementation are

  • Tight coupling between classes (Order is tightly coupled with PayementGateway and InventorySystem)
  • Not easy to change implementation because to change the implementation we need to change the implementation of the Order class and it will violate the Open Close Principle.
  • Difficult to test

Dependency Injection

Dependency Injection is a technique that is used to allow calling code to inject dependencies a class needs when it is instantiated. It also goes by the name of the Hollywood principle (“Don’t call us, we’ll call you!”). So instead of creating an instance of the PaymentGateway we should be able to call some service to charge the credit card.

There are 3 popular techniques for Dependency injection

Constructor Injection

This is implemented by the use of strategy pattern wherein the dependencies are passed in the constructor of class. So the constructer specifies the dependencies it need to function completely and the calling code about the dependencies of the class.

 

Pros

  • Class declares upfront what it needs to function properly
  • Class will always be in a valid state once constructed as it does not have any other dependency than the ones explicitly mentioned in the constructor.

Cons

  • Constructors might end up having too many parameters (design smell)
  • Some methods in the class might not use all the parameters passed in the constructor (design smell)
  • Some features like serialization might need a default constructor as well.

Property Injection

In this type of injection we pass the dependencies via properties. It is also known as setter injection.

Pros

  • Flexible as the dependency can be changed at any time.

Cons

  • Objects may be in inconsistent state between construction and setting of dependency.

Parameter Injection

In this type of injection we pass the dependencies in the method directly as parameters.

Pros

  • Gives us the granular level control on the dependencies that we need to inject
  • More flexible as we don’t need to modify anything in the rest of the class other than the method we are changing.

Cons

  • The method itself might end up with many parameters (design smell)
  • If we change the method signature then we might need to make changes at the places where this method is being used.

Where to instantiate objects

Now that we have made the implementation of the order class without any instantiations then where do we instantiate the dependencies. Below are few common places where we can instantiate the dependencies.

Default Constructor

We could have a default constructor that would instantiate the dependencies needed in the application. This approach is referred as poor man’s IoC

Main

We can instantiate the dependencies we need in the Main method of the application or startup routine of the application.

IoC Container

We could use an Inversion of Control (IoC) container.  IoC containers are responsible for object graph instantiation and the initiation happen when the application begins and IoC’s generally use code or configurations to figure out what is set up to use when an Interface is called for. We need to register the managed interfaces and implementations with the container and then the dependencies on Interfaces is resolved at application startup or runtime.

Few of the IoC containers available in .NET are

  • Microsoft Unity
  • StructureMap
  • Ninject
  • Windsor
  • Funq / Munq

 

 

Find the complete source code for this post at googledrive or skydrive.

Any questions comments and feedback are most welcome.

SOLID Design Principles – Interface Segregation Principle (ISP)

 

The Interface Segregation Principle states that the clients should not be forced to use the methods that they do not use.

 

SOLID Design Principles   Interface Segregation Principle (ISP)The above image depicts the complex interface with switches and buttons for the usb to work but the end user does not care about this complexity. The end use just needs to know where to plug-in the usb for the usb to work. An Interface is a non-implementable type that specifies a public set of methods and properties that are implemented by the type that chooses to implement that interface. An Interface could also be the public interface of a class where it exposes the public methods and properties of the class. Now if some client needs only a part of the functionality then we should be able to better design the interfaces or sub-class so that the client in not forced to use what it does not need. Let us take the example of a store that takes order both online as well as in the store. In the online order the store accepts credit cards but in the store order it accepts only cash. So have an Interface IOrder as shown below:

And both the OnlineOrder class and InStoreOrder class implement this interface.

 

In the above implementation we are violating the Interface Segregation Principle because the InStoreOrder class implements the IOrder interface but it does not implement one of the methods ProcessCreditCard. Let’s improve the solution to follow Interface Segregation Principle. To do that we will break the IOrder interface and create another Interface IOnlineOrder which will have the ProcessCreditCard method. So now the interfaces will look like below.

So our existing implementations could still remain the same and new the implementation that need online part of the functionality will use the implement the required interface only.

 

SOLID Design Principles – Liskov Substitution Principle (LSP)

 

Liskov Substitution Principle can be considered to be an extension of the Open / Closed principle which states the base class reference should be replaceable by the child class without changing the functionality.

SOLID Design Principles   Liskov Substitution Principle (LSP)

Let us assume that we implemented a Rectangle class with height, width properties and getArea method. Alone it will function perfectly fine.

 

Now we would like to have a similar functionality for a Square as well, so instead on reinventing the wheel we will simply inherit from the Rectangle class and customize the functionality for a square.

 

But now if we replace the reference of the parent class by the child class then we will not the correct area for the rectangle since we have change the core functions (setHeight, setWidth) to set the height and width to same value which is not true in case of rectangle. Hence we have violated the Liskov Substitution principle.

Output:

Area of the rectangle = 2400 where Height = 40 and Width = 60

Output:

Area of the rectangle = 3600 where Height = 60 and Width = 60

It is clear that the Square type is not substitutable for the Rectangle. LSP states that we should be able to the child classes should be able to extend the base classes without changing their existing functionality and we are violating that in this implementation as our square class is changing the behavior of the rectangle class.

Generally speaking the non-substitutable code will break polymorphism.

We can fix this code by creating a class (Shape) from which both Rectangle and Square inherit from. So as we could see in the code below, we have created an abstract class shape with an abstract method GetArea.

We will now inherit this class in Rectangle and Square and provide the individual implementation of GetArea.

We could use the Shape class to get the area of the shapes.

Output

Area of the rectangle shape = 2400

Area of the square shape = 1600

So now the parent class is substitutable by the child classes without changing any existing functionality and so we are not violating the Liskov Substitution Principle.

 

Find the complete source code for this post at googledrive or skydrive.

Any questions comments and feedback are most welcome.

SOLID Design Principles – Open / Closed Principle (OCP)

 

The Open / Closed principle states

“Software entities (classes, modules, functions, etc.) should be open for extension, but closed for modification” - Wikipedia

Open to extension means that we should be able to add new behavior or features to a class and Closed for modification means that while making these changes we should not need to modify the binaries.

If we want to add new behavior that we should not need to change the existing classes or functions. We should just be able to add new classes and functions to achieve this. A simple example is that we do not need to rewire the motherboard to plug in a USB.

SOLID Design Principles   Open / Closed Principle (OCP)

Now you might be thinking how can we achieve extension without making any modifications to a binary?

The answer lies in abstraction.  Once we start relying on abstractions then we many ways to apply the open close principle. In .NET we can achieve this abstraction through Interfaces and Abstract classes.

When we want to add new behavior, then we need to write new functions and new classes and this helps a single class in focus on one thing and we end up with small, easier to maintain classes. Also when we write new classes then none of the existing code is dependent on this new code and hence unlikely to introduce bug.

We can add seams to the applications which allows us to create the demarcation between different layers.

 

Approaches for achieving Open/Closed principle

Parameters

We could pass some information as parameters which could help us avoid the modifications. For example we create a simple program to clean up temporary files on my computer at 9AM. Now I share this code on my blog and people start using it but soon people start asking for a simple modification of allowing the users to decide the time for the cleanup to run. Now if I would have allowed this time to be a user inputted parameter then my class and function would have not needed any modifications.

Inheritance

Inheritance is another way to achieve the open close behavior. In heritance we allow the child classes to change and extend the behavior without making any changes to the parent classes.

Composition

To achieve Composition we could use the Strategy pattern. The strategy pattern allows us to follow the plugin model where the class doing the work gets injected into the class that needs that behavior. In this case we have a level of abstraction between the calling code and called code. In this type of approach the Implementation class used Inheritance since that will inherit from the base for some implementation and the client class follows composition since it exposes itself for other classes to pass into itself.

Example

Let us take the example of a class that calculates the area of a rectangle

 

To get the area of a rectangle we will pass the object of the Rectangle class and get the area back.

Now we would like to extend the AreaCalculator to calculate the area of a circle as well.

So we will change the AreaCalculator to something like below. So depending on the shape we can calculate the area of the shape.

However if tomorrow we want to extend the AreaCalculator class to include another shape then we will have to modify the class again.

 

Now let us try to implement the AreaCalculator class following the Open / Closed principle. Let’s start by creating an abstraction for shape. We will create a class named shape that exposes a method Area.

Now whenever we want to create a Shape we will inherit from this abstract class. Let us now create Rectangle and Circle classes inheriting from Shape. We will provide individual implementation of Area and also add the properties as applicable for each shape.

Since each shape has its own implementation of Area so our AreaCalculator becomes much simpler and robust.

 

And since the new classes bring in their own implementations we do not need to modify the existing functionality because of the new behaviors that we add.

 

Find the complete source code for this post at googledrive or skydrive.

Any questions comments and feedback are most welcome.

 

 

SOLID Design Principles – Single Responsibility Principle (SRP)

 

Hey guys,

In this series i will talk about the SOLID Design Principles. We will discuss one principle in each post.

In this post we will talk about the S which is Single Responsibility Principle (SRP).

 

Single Responsibility Principle (SRP)

 

There should never be more than one reason to change a class. Robert C. Martin

We can think of responsibility of a class as a reason for change in the context of SRP and we want a class to have only one of that. This will be really important when we have an issue because we will know exactly we need to look.

SOLID Design Principles   Single Responsibility Principle (SRP)

Say we have a modem class in our application and it does 4 operations

 

SOLID Design Principles   Single Responsibility Principle (SRP)

Without SRP



 

It will make a lot of sense to divide these operations into 2 interfaces that the Modem class implements. We have divided responsibility so that each class has single reason to be modified.

 

SOLID Design Principles   Single Responsibility Principle (SRP)

With SRP

This does not mean that we should start creating different classes for each of the feature or method that we are implementing. There can be different levels of segregation that we can have depending on our application.

For example – In a huge application we might want to create a math class for doing all the math related operations but in a small application we might have different classes for simple operations (add, sub, mul, div) and different class for trigonometric operations (sin, tan, cos)

Cohesion – It is a measure of how much responsibility, data and methods of a class / module are related. It can be thought of as the clarity with which the role of a class is defined within the system. We should always aim for high cohesion.

We can identify cohesion by comparing the class name and the responsibility of the class. If the class is doing something other than what its name specifies than we do not have the desired level of cohesion.

Put your code where everyone would expect to find it.

Coupling – It is the degree to which the different modules or classes are interdependent or relies on each other. We should always aim for low coupling.

The more responsibility a class has more is the likelihood of changes in the class, more the changes more is the likelihood of errors because the responsibilities within a class tend to couple with each tightly.

Interface Segregation Principle (ISP) helps us achieve the Single Responsibility Principle (SRP).

 

Any questions, comments or feedback is welcome.