Wednesday, 25 May 2016

Interface Segregation Principle (ISP)

=> The principle states that no client should be forced to depend on methods that it doesn't use.
=> A client should never be forced to implement an interface that it doesn't use or client shouldn't be forced to depend on methods that they don't use.

Here we give an example of ISP violation and then refactor that violation. Without talking unnecessary things let's jump into the code.

ISP violation :
public interface IMessage{
 IList<string> ToAddress {get; set;}
 IList<string> BccAddresses {get; set;}
 string MessageBody {get; set;}
 string Subject {get; set;}
 bool Send();
}

public class SmtpMessage : IMessage{
 public IList<string> ToAddress {get; set;}
 public IList<string> BccAddresses {get; set;}
 public string MessageBody {get; set;}
 public string Subject {get; set;}
 public bool Send(){
  // Code for sending E-mail.
 }
}

public class SmsMessage : IMessage{
 public IList<string> ToAddress {get; set;}
 public IList<string> BccAddresses {
  get { throw new NonImplementedException(); }
  set { throw new NonImplementedException(); } 
 }
 public string MessageBody {get; set;}
 public string Subject {
  get { throw new NonImplementedException(); }
  set { throw new NonImplementedException(); } 
 }
 public bool Send(){
  // Code for sending SMS.
 }
}
In the SmsMessage we don't need BccAddresses and Subject, but we forced to implement it because of IMessage interface . So it's violate the ISP principle.

Remove violation :
public interface IMessage{
 bool Send(IList<string> toAddress, string messageBody);
}

public interface IEmailMessage : IMessage{
 string Subject {get; set;}
 IList<string> BccAddresses {get; set;}
}

public class SmtpMessage : IEmailMessage{
 public IList<string> BccAddresses {get; set;}
 public string Subject {get; set;}
 public bool Send (IList<string> toAddress, string messageBody){
  // Code for sending E-mail.
 }
}

public class SmsMessage : IMessage{
 public bool Send (IList<string> toAddress, string messageBody){
  // Code for sending SMS.
 }
}
SmsMessage need only toAddress and messageBody, so now we can use IMessage interface to avoid unnecessary implementations.

Monday, 23 May 2016

Liskov Substituton Principle (LSP)


=> Child class should never break the parent class type definition.
=> An object should be substitutable by its base class (or interface).

LSP violation code :
public interface IPersistedResource{
 void Load();
 void Persist();
}

public class ApplicationSettings : IPersistedResource{
 public void Load(){
  // Function definition for ApplicationSettings
 }

 public void Persist(){
  // Function definition for ApplicationSettings
 }
}

public class UserSettings : IPersistedResource{
 public void Load(){
  // Function definition for UserSettings
 }

 public void Persist(){
  // Function definition for UserSettings
 }
}
Use :
static IEnumerable<IPersistedResource> LoadAll(){

 var allResources = new List<IPersistedResource>
  {
   new UserSettings(),
   new ApplicationSettings()
  };

 allResources.ForEach(r => r.Load());

 return allResources;
}

static void SaveAll(IEnumerable<IPersistedResource> resources){
 resources.ForEach(r => r.Persist());
}

IEnumerable<IPersistedResource> resources = LoadAll(); // Should be a happy user with loaded resources

SaveAll(resources); // Should be a happy user with saved persist

Everything works great, until a new class is added to the system inorder to handle, let's add another class "SpecialSettings"
public class SpecialSettings : IPersistedResource{
 public void Load(){
  // Function definition for SpecialSettings
 }

 public void Persist(){
  through new NotImplementedException();
 }
}

static IEnumerable<IPersistedResource> LoadAll(){

 var allResources = new List<IPersistedResource>
  {
   new UserSettings(),
   new ApplicationSettings(),
   new SpecialSettings()
  };

 allResources.ForEach(r => r.Load());

 return allResources;
}

static void SaveAll(IEnumerable<IPersistedResource> resources){
 resources.ForEach(r => {
  if(r is SpecialSettings)
   return;
  r.Persist();
  });
}
Here, marked code is the violated for SpecialSettings(). Because we know An object should be substitute by its base class or interface".

Now it is time to refactor the violation. Let's refactor this violation :
public interface ILoadResource{
 void Load();
}

public interface IPersistedResource{
 void Persist();
}

public class ApplicationSettings : ILoadResource, IPersistedResource{
 public void Load(){
  // Function definition for ApplicationSettings
 }

 public void Persist(){
  // Function definition for ApplicationSettings
 }
}

public class UserSettings : ILoadResource, IPersistedResource{
 public void Load(){
  // Function definition for UserSettings
 }

 public void Persist(){
  // Function definition for UserSettings
 }
}

public class SpecialSettings : ILoadResource{
 public void Load(){
  // Function definition for SpecialSettings
 }
}
Use :
static IEnumerable<ILoadResource> LoadAll(){

 var allResources = new List<ILoadResource>
  {
   new UserSettings(),
   new ApplicationSettings(),
   new SpecialSettings()
  };

 allResources.ForEach(r => r.Load());

 return allResources;
}

static void SaveAll(IEnumerable<IPersistedResource> resources){
 resources.ForEach(r => r.Persist());
}

Friday, 20 May 2016

Open Closed Principle (OCP)

Software entities (class, modules, functions, etc) should be open for extension but closed for modification. Here, we try to explain OCP using codebase. First we'll show a scenario that violate OCP and then we'll remove that violation.

Area Calculation (OCP violation Code) :
public class Rectangle{
 public double Width {get; set;}
 public double Height {get; set;}
}

public class Circle{
 public double Radious {get; set;}
}

public double getArea (object[] shapes){
 double totalArea = 0;

 foreach(var shape in shapes){
  if(shape is Rectangle){
   Rectangle rectangle = (Rectangle)shape;
   totalArea += rectangle.Width * rectangle.Height;
  }
  else{
   Circle circle = (Circle)shape;
   totalArea += circle.Radious * circle.Radious * Math.PI;
  }
 }
}
Now if we need to calculate another another type of object (say, Trapezium) then we've to add another condition. But from the rule's of OCP we know Software entities should be closed for modification. So it is the violation of OCP.

Ok. Let's try to solve this violation implementing OCP.
public abstract class shape{
 public abstract double Area();
}

public class Rectangle : shape{
 public double Width {get; set;}
 public double Height {get; set;}

 public override double Area(){
  return Width * Height;
 }
}

public class Circle : shape{
 public double Radious {get; set;}

 public override double Area(){
  return Radious * Radious * Math.PI;
 }
}

public double getArea (shape[] shapes){
 double totalArea = 0;

 foreach(var shape in shapes){
  totalArea += shape.Area();
 }

 return totalArea;
}
Now when we need to calculate another type of object, we don't need to change logic here (in getArea()), we just have to add another class like Rectangle or Circle..

Saturday, 14 May 2016

Single Responsibility Principle (SRP)

There should never be more than one reason for change anything in software entities (class, function, file etc). A class, function, file etc should have only one reason to change. Let's go through the problem first. Have a look at the code given below :
public class BankAccount
{             
    public BankAccount()  {}

    public string AccountNumber { get; set; }
    public decimal AccountBalance { get; set; }

    public decimal CalculateInterest()
    {
        // Code to calculate Interest
    }
}
Here, BankAccount class contains the properties of account and also calculate the interest of account. Now look at the few change Request we received from business:

1. Please add a new Property AccountHolderName .
2. Some new rule has been introduced to calculate interest.

This are totally different type of change request. One is changing on features; where as other one is impacting the functionality. We have 2 different types of reason to change one class. This violates Single Responsibility Principle.

Now let's try to implement SRP to resolved this violation. Look at the code below:
public interface IBankAccount
{
    string AccountNumber { get; set; }
    decimal AccountBalance { get; set; }
}

public interface IInterstCalculator
{
    decimal CalculateInterest();
}

public class BankAccount : IBankAccount
{
    public string AccountNumber { get; set; }
    public decimal AccountBalance { get; set; }
}

public class InterstCalculator : IInterstCalculator
{
    public decimal CalculateInterest(IBankAccount account)
    {
        // Write your logic here
        return 1000;
    }
}
Now our BankAccount class is just responsible for properties of the bank account. If we want to add any new business rule for the Calculation of Interest, we don't need to change BankAccount class.

And also InterestCalculator class requires no changes, in case we need to add a new Property AccountHolderName. So this is the implementation of Single Responsibility Principle.

We have also used Interfaces to communicate between InterestCalculator and BankAccount class. This will help us to manage dependencies between classes.