Quote for the Week

"Learn to enjoy every moment of your life"

Friday, January 30, 2015

S.O.L.I.D Architecture principle in C# (Part 5)

Continue to Thursday, January 29, 2015
------------------------------------------------------

Dependency Inversion Principle (DIP)


Dependency Inversion Principle or DIP states that:

High-level modules should not depend on low-level modules. Both should depend on abstractions. 
Abstractions should not depend on details. Details should depend on abstractions.

Consider that you are developing an application that deals with user management (creating a user, managing their passwords, etc.). After every user management task you wish to send a notification to the user as well as to the administrator about the activity performed. The following code shows a simplified implementation of this system.

public class EmailNotifier
{
    public void Notify(string email, string message)
    {
        //send email here
    }
}

public class UserManager
{
    EmailNotifier notifier = new EmailNotifier();

    public void CreateUser(string userid,string password,string email)
    {
        //create user here
        notifier.Notify(email, "User created successfully!");
    }

    public void ChangePassword(string userid, string oldpassword,string newpassword)
    {
        //change password here
        notifier.Notify(email, "Password changed successfully");
    }
}
The EmailNotifier class has just one method - Notify() that accepts an email address and a notification message. Inside, it sends an email to the specified address notifying the user of the change. The UserManager class declares an instance of EmailNotifier class and uses it in methods such as CreateUser() and ChangePassword(). So far so good. Now assume that instead of email notification you want to send SMS based notifications. To cater to this change you not only need to write another class (say SMSNotifier) but also need to change UserManager class because UserManager uses EmailNotifier. This problem arises due to the fact that high level module UserManager depends on a concrete low level module EmailNotifier.

Let's change our classes to follow DIP.

public abstract class NotifierBase
{
    public abstract void Notify(string message);
}

public class EmailNotifier:NotifierBase
{
    public string EmailAddress { get; set; }
    public override void Notify(string message)
    {
        //send email here
    }
}

public class SMSNotifier : NotifierBase
{
    public string MobileNumber { get; set; }
    public override void Notify(string message)
    {
        //send SMS here
    }
}

public class UserManager
{
    public NotifierBase Notifier { get; set; } 

    public void CreateUser(string userid,string password,string email)
    {
        //create user here
        Notifier.Notify("User created successfully!");
    }

    public void ChangePassword(string userid, string oldpassword,string newpassword)
    {
        //change password here
        Notifier.Notify("Password changed successfully");
    }
}
Now, the code defines an abstract class NotifierBase that defines the Notify() method. The two classes EmailNotifier and SMSNotifier inherit from the NotifierBase class and provide the necessary implementation details. More importantly the UserManager class no longer uses a specific concrete implementation. It uses a NotifierBase abstraction in the form of the Notifier public property. This public property can be set by the consumer of the UserManager class either to an instance of EmailNotifier class or to an instance of SMSNotifier class or any other class that inherits from NotifierBase class. Thus our code now depends on abstractions and not on the concrete implementation.

Summary

SOLID principles of object oriented programming allow you to write structured and neat code that is easy to extend and maintain. SOLID principles include Single Responsibility Principle (SRP), Open/Closed Principle (OCP), Liskov Substitution Principle (LSP), Interface Segregation Principle (ISP) and Dependency Inversion Principle (DIP).


No comments: