Liskov Substitution Principle

If you’ve been following my blog,you’ll know that we have been covering the SOLID Principles,in my previous posts i covered The Single Responsibility Principle,the “S” in the SOLID Acronym,then we covered The Open Closed Principle,today  my focus will be on The Liskov Substitution Principle,the “L” in the SOLID Principles acronym.

What is LSP?

This principle is credited to Barbara Liskov,she wrote this principle in 1988 and she said:

“What is wanted here is something like the following substitution property: If for each object o1
of type S there is an object o2 of type T such that for all programs P defined in terms of T, the
behaviour of P is unchanged when o1 is substituted for o2 then S is a sub-type of T.”

In simple terms the above statement means:

“Subtypes must be substitutable for their base types.”

or more simply:

“It means that we must make sure that new derived classes are extending the base classes without changing their behaviour” 

A Simple Example Using C#

We’ll use the classic Rectangle-Square problem to demonstrate this principle. Let’s imagine that we need to find the area of any rectangle.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;


namespace SOLIDPrinciplesDemo
{
  // If any module is using a Base class then the reference to that Base class can be replaced with a Derived class without affecting the functionality of the module.
  // Or
  // While implementing derived classes, one needs to ensure that, derived classes just extend the functionality of base classes without replacing the functionality of base classes.

class Rectangle
{
 protected int mWidth = 0 ;
 protected int mHeight = 0;

public virtual void SetWidth(int width)
{
  mWidth = width;
}

public virtual void SetHeight(int height)
{
  mHeight = height;
}


public virtual int GetArea()
{
  return mWidth * mHeight;
}
}


  // While implementing derived class if one replaces the functionality of base class then,
  // it might result into undesired side effects when such derived classes are used in existing program modules.
class Square : Rectangle
{
  // This class modifies the base class functionality instead of extending the base class functionality
  // Now below methods implementation will impact base class functionality.
public override void SetWidth(int width)
{
  mWidth = width;
  mHeight = width;
}

public override void SetHeight(int height)
{
  mWidth = height;
  mHeight = height;
}

}


class LiskovSubstitutionPrincipleDemo
{

private static Rectangle CreateInstance()
{
  // As per Liskov Substitution Principle "Derived types must be completely substitutable for their base types".
  bool SomeCondition = false;

if (SomeCondition == true)
{
  return new Rectangle();
}
else
{
  return new Square();
}
}

public static void LSPDemo()
{
  Console.WriteLine("\n\nLiskov Substitution Principle Demo ");
  Rectangle RectangleObject = CreateInstance();

  // User assumes that RectangleObject is a rectangle and (s)he is able to set the width and height as for the base class
  RectangleObject.SetWidth(5);
  RectangleObject.SetHeight(10);
  // Now this results into the area 100 (10 * 10 ) instead of 50 (10 * 5).
  Console.WriteLine("Liskov Substitution Principle has been violated and returned wrong result : " + RectangleObject.GetArea());
  // So once again I repeat that sub classes should extend the functionality, sub classes functionality should not impact base class functionality.
}
}
}

I know the example above doesn’t exhaust the LSP principle,but im sure it gave you an idea what the principle stands for.

Benefits

This principle aims to keep functionality intact. The main purpose is to guarantee that objects lower in a relational hierarchy can be treated as though they are objects higher in the hierarchy. Basically, any child class should be able to do anything the parent can do.

Further Reading

1.Data Abstraction and Hierarchy,” Barbara Liskov, SIGPLAN Notices, 23(5) (May 1988)

2.Bertrand Meyer, Object-Oriented Software Construction, 2d. ed., Prentice Hall, 1997

3.Rebecca Wirfs-Brock et al. , Designing Object-Oriented Software, Prentice Hall,
1990.

4.Agile.Principles.Patterns.and Practices.In.C#[Robert.C.Martin]

That’s it for this week,next i will be covering Interface Segregation Principle(ISP),the letter “I” in the SOLID acronym.

****Happy Holidays and be safe****

The Open Closed Principle

Last week I covered the Single Responsibility Principe, which is part of the SOLID Principles, this week I will continue and cover the next principle  which is the Open/Closed Principle.

What is The Open Closed Principle?

Robert “Uncle Bob”  Martín, defines it like this:
The open/closed principle states “software entities (classes, modules, functions, etc.) should be open for extension, but closed for modification”; that is, such an entity can allow its behaviour to be extended without modifying its source code.

Simply stated, this means that we should not have to change our code every time a requirement or a rule changes. Our code should be extensible enough that we can write it once and not have to change it later just because we have new functionality or a change to a requirement.

Imagine what life would be like if every new feature or requirement resulted in changing the source code, that would mean that one has to  test the code again and again, that would be a tedious thing, lest to say boring.

*Code Example

Let me illustrate with a code example

Background

 We were working on a project where we were using Oracle as the prime repository until one fine day our technical lead came up and announced that our application should support SQL Server as another data source.

Now our Data access layer had a DBConnection class with a connect method strongly bound to accept Oracle provider and establish a connection.

I ignored the detailed implementation and tried to keep things simple.

Initial Code

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace SOLID
{
    class DBConnection
    {
        public void Connect(OracleProvider ora)
        {
            Console.WriteLine("Connected to oracle data source");
        }
    }

    class OracleProvider
    {
        string _providername;
    }
}

As we were in a hurry for the delivery, we could only come up with this design for the existing dbConnection class so that it now supports SQL provider too.

After Refactoring

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace SOLID
{
    class DBConnection
    {

        public void Connect(object o)
        {

            if (o is OracleProvider)
            {
                Console.WriteLine("Connected to oracle data source");
            }
            else if (o is SQlProvider)
            {
                Console.WriteLine("Connected to sql data source");
            }
        }
    }

    class OracleProvider
    {
        string _providername;
    }

    class SQlProvider
    {
        string _providername;
    }
}

OMG ! We designed something wrong …

Here if you can see from the above code, we are modifying the class DBConnection rather than extending it by including if else statements, this simply is against OCP.

Reason is simple if tomorrow another provider is introduced, again we have to make changes to the DBconnection class.

Ultimate refactoring …

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace SOLID
{
    interface IDBConnection
    {
        public void Connect();
    }

    class DBConnection
    {
        public void Connect(IDBConnection con)
        {
            con.Connect();
        }
    }

    class OracleProvider :IDBConnection
    {
        string _providername;

        public void Connect()
        {
            Console.WriteLine("Connected to oracle data source");
        }        
    }

    class SQlProvider:IDBConnection
    {
        string _providername;

        public void Connect()
        {
            Console.WriteLine("Connected to sql data source");
        }        
    }
}

Finally the main method ….

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace SOLID
{
    class Program
    {
        static void Main(string[] args)
        {
            //Sql connection 
            IDBConnection conSQl = new SQlProvider();
            conSQl.Connect();

            //oracle connection 
            //IDBConnection conOra = new SQlProvider();
            //conOra.Connect();
        }       
    }
}

The above design we could come up seems to adhere to OCP.
Now tomorrow if we have to support another Data source, we can easily do it by simply extending IDBConnection needless to make any changes to DBConnection.

So the entities are now open for extension and closed for modification.

That’s it for this week, will be looking at the the Liskov Substitution Principle next,which is the letter “L” in the SOLID Principles acronym.

*Code example adapted from an article in code project

Design Principles To Increase Your Productivity As A Developer

Today I will tackle a topic that new to intermediate software developers struggle with, that’s a concept of design principles,if you master the design principles it will greatly improve your productivity as a software developer.

I know in some large organisations I know there is a person responsible for implementing the design principles or enforce them or ensures that they are implemented during software development.

In the following weeks I will be covering a concept called the SOLID principles, covering one or two concept per week.

First let me define what solid principles are. SOLID is actually an acronym for

S-Single Responsibility Principle(SRP)

O-Open/Closed principle(OCP)

L-Liskov Substitution Principle(LSP)

I-Interface Segregation Principle(ISP)

D-Dependency Inversion Principle(DIP)

5 TOOLS AND TECHNOLOGIES EVERY DEVELOPER SHOULD MASTER

THE SINGLE RESPONSIBLE PRINCIPLE

singleresponsibilityprinciple

Single responsible principle

Robert “Uncle Bob” Martin in his book: Agile Principles Patterns and Principles in C# states:

“A class should have only one reason to change “

Like life if you focus on so many things you will fail, in the same way If a class has more than one responsibility, the responsibilities become coupled. Changes to one responsibility may impair or inhibit the class’s ability to meet the others. This kind of coupling leads to fragile designs that break in unexpected ways when changed.

Like in the image above,the pocket knife is a super knife it can do almost everything,but in the process of adding all the components that make it a super knife it has lost its real purpose that is being a pocket knife.

In the same way you can overload a class with a lot of functionality to a point that it loses its identity

Let me illustrate with a C# code example

The following C# example shows a class named “RectangleShape” that implements two methods, one that calculates its rectangle area and one that draws the rectangle. When the area calculation changes for some reason or the drawing method has to change, for example, another fill color is used, then the whole class is under change. Also if the properties are altered, it influences both methods. After a code change, the class must be tested as a whole again. There is clearly more than one reason to change this class.

Problem

/// <summary>
/// Class calculates the area and can also draw it on a windows form object.
/// </summary>

    public class RectangleShape
    {
        public int Height{ get; set; }
        public int Width { get; set; }
 
        public int Area()
        {
            return Width * Height;
        }
 
        public void Draw(Form form)
        {
            SolidBrush myBrush = new SolidBrush(System.Drawing.Color.Red);
            Graphics formGraphics = form.CreateGraphics();
            formGraphics.FillRectangle(myBrush, new Rectangle(0, 0, Width, Height);
        }
    }

Typically, the above class is used by consuming client classes like these:

/// <summary>
/// Consumes the RectangleShape */
/// </summary>
    public class GeometricsCalculator
    {
        public void CalculateArea(RectangleShape rectangleShape)
        {
            int area = rectangleShape.Area();
        }
    }   


/// <summary>
//// Consumes the RectangleShape */
/// </summary>
    public class GraphicsManager
    {
        public Form form {get;set;}

        public void DrawOnScreen(RectangleShape rectangleShape)
        {
            rectangleShape.Draw(form);
        }
    }

Solution

The next classes show how to separate the different responsibilities. Basic coding is used not taking other SOLID principles into account. It only just shows how to deal with the SRP principle. The RectangleDraw class consumes now a RectangleShape instance and a Form object.

/// <summary>
/// Class calculates the rectangle's area.
/// </summary>
    public class RectangleShape
    {
        public int Height { get; set; }
        public int Width { get; set; }

        public int Area()
        {
            return Width * Height;
        }
    }

/// <summary>
/// Class draws a rectangle on a windows form object.
/// </summary>
    public class RectangleDraw
    {
        public void Draw(Form form, RectangleShape rectangleShape)
        {
            SolidBrush myBrush = new SolidBrush(System.Drawing.Color.Red);
            Graphics formGraphics = form.CreateGraphics();
            formGraphics.FillRectangle(myBrush, 
            new Rectangle(0, 0, rectangleShape.Width,rectangleShape.Height));
        }
    }

The following code shows how to consume both classes:

/// <summary>
/// Consumes the RectangleShape */
/// </summary>
    public class GeometricsCalculator
    {
        public void CalculateArea(RectangleShape rectangleShape)
        {
            int area = rectangleShape.Area();
        }
    }

/// <summary>
/// Consumes the RectangleDraw and RectangleShape */
/// </summary>
    public class GraphicsManager
    {
        public Form form { get; set; }
        
        public void DrawOnScreen(RectangleDraw rectangleDraw, RectangleShape rectangleShape)
        {
            rectangleDraw.Draw(form, rectangleShape);
        }
    }

Before i wrap up for today let me point out the advantages:

Major benefits of this pattern are

  • Code complexity is reduced by being more explicit and straightforward

  • Loose coupling

  • Improved readability