Click here to Skip to main content
15,868,019 members
Articles / Programming Languages / C#

Learning the S.O.L.I.D Programming Principles: Liskov Substitution Principle [Part – IV]

Rate me:
Please Sign up or sign in to vote.
0.00/5 (No votes)
22 Nov 2015CPOL4 min read 6.1K   5   3
Liskov substitution principle [Part – IV]

History

In our previous posts, we learned ‘What is S.O.L.I.D. Programing Principles’ and a detailed explanation with code of Single Responsibility Principle and Open/closed Principle.

S.O.L.I.D. is an acronym introduced by Michael Feathers as:

  1. S for SRP: Single responsibility principle
  2. O for OCP: Open/closed principle
  3. L for LSP: Liskov substitution principle
  4. I for ISP: Interface segregation principle
  5. D for DIP: Dependency inversion principle
  • Single Responsibility Principle says, class should have single responsibility. In reference to this, I would say “A class should have single responsibility”.
    Let's dive into ocean – can we read this like “a class should not design to do multiple activities”.
  • Open/Closed Principle says, “software entities (classes, modules, functions, etc.) should be open for extension, but closed for modification”.

Learning S.O.L.I.D is a very vast topic and it is not possible to explore it in one-shot. I divided this into the following parts:

Introduction

In this whole article, we will learn Liskov Substitution Principle in details with an example.

Here is the definition from wiki:

“if S is a subtype of T, then objects of type T may be replaced with objects of type S (i.e., objects of type S may be substituted for objects of type T)
without altering any of the desirable properties of that program (correctness, task performed, etc.)”

Learning Liskov Substitution Principle (LSP)

I understood the above definition like this: parent should easily replace the child object.

Let's explore this with an example: Go back to code discussed during our previous session and suppose we have several databases, some of these should not be migrated.

Take a look into the following snippet:

C#
public class DataBase
{
	public virtual bool IsValid(ServerData data, SourceServerData sourceData)
	{
		return new Validator(new List<IValidator>()).Validate(data, sourceData);
	}

	public virtual void Save()
	{
		//logic to save data
	}
}

public class ProdDB : DataBase
{
	public override bool IsValid(ServerData data, SourceServerData sourceData)
	{
		return base.IsValid(data, sourceData);
	}

	public override void Save()
	{
		//logic to save data
		base.Save();
	}
}

public class QADB : DataBase
{
	public override bool IsValid(ServerData data, SourceServerData sourceData)
	{
		return base.IsValid(data, sourceData);
	}

	public override void Save()
	{
		//logic to save data
		base.Save();
	}
}

public class LocalDB : DataBase
{
	public override bool IsValid(ServerData data, SourceServerData sourceData)
	{
		return base.IsValid(data, sourceData);
	}

	public override void Save()
	{
		throw new Exception("Local Data should not be saved!");
	}
}

Recall, inheritance and you can visualize that DataBase is a parent class of ProdDB, QADB and LocalDB.

Let's think polymorphism for a while and we can write as:

C#
DataBase pDataBase = new ProdDB();
DataBase qDataBase = new QADB();
DataBase lDataBase = new LocalDB();

//also can create a list of DataBase type
var dataBases = new List<DataBase> {new ProdDB(), new QADB(), new LocalDB()};

Isn’t it easy to save my object using this:

C#
var dataBases = new List<DataBase> {new ProdDB(), new QADB(), new LocalDB()};

foreach (var dataBase in dataBases)
{
	if (dataBase.IsValid(data, sourceData))
		dataBase.Save();
}

Wait, wait…

What's wrong in the above, NOTHING?

Yes, you are absolutely correct. There is nothing wrong with the above code, the only thing is, its execution. When the above code executes, it will also invoke save method of LocalDB object. In this case, we received an exception as our LocalDB object is not supposed to save data.

A big question is “why this happened?”
In simple words, LocalDB is actually not an entity of DataBase or we can say DataBase is not an actual parent of LocalDB.

Another question in mind “Why LocalDB is not an entity of DataBase, when it inherits DataBase“.
Hold on, go back to LocalDB class and check this is not meant to implement Save() method, here this makes LocalDB as a separate entity.

In simple words, LISCOV says parent should easily replace its child.

How to Implement LISCOV Principle?

We know LocalDB is not supposed to save data, but others are. Let's consider the following snippet:

C#
public interface IRule
{
	bool IsValid(ServerData data, SourceServerData sourceData);
}

public interface IRepository
{
	void Save();
}

Now, we have two interfaces, with their own methods. IRule: to validate data and IRepository: to save/persist data.

Let's make changes to our LocalDB class, as:

C#
public class LocalDB : IRule
{
	public bool IsValid(ServerData data, SourceServerData sourceData)
	{
		return new Validator(new List<IValidator>()).Validate(data, sourceData);
	}
}

Why We Implement IRule?

For LocalDB, we only want to check whether data is valid or not. We do not want to persist data in any scenario.

Now, we can’t write this:

C#
DataBase lDataBase = new LocalDB();

Our DataBase class should be like this:

C#
public class DataBase : IRule, IRepository
{
	public virtual bool IsValid(ServerData data, SourceServerData sourceData)
	{
		return new Validator(new List<IValidator>()).Validate(data, sourceData);
	}

	public virtual void Save()
	{
		//logic to save data
	}
}

Other classes will remain unchanged.

Our execution code goes as:

C#
public void Execute(ServerData data, SourceServerData sourceData)
{
	var dataBases = new List<IRepository> { new ProdDB(), new QADB() };

	foreach (var dataBase in dataBases.Where(dataBase => ((IRule)dataBase).IsValid(data, sourceData)))
	{
		dataBase.Save();
	}
}

Now, our code looks much easier to handle. :)

How to Download the Source Code?

You can download the complete souce code of examples used in this article from GitHub: Learning Solid.

The post Learning The S.O.L.I.D Programming Principles: Liskov substitution principle [Part – IV] appeared first on Gaurav-Arora.com.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Chief Technology Officer
India India
Learning never ends.

Comments and Discussions

 
QuestionLinks are b0rked Pin
Member 1140848923-Nov-15 23:42
Member 1140848923-Nov-15 23:42 
QuestionDefinition is not quite correct Pin
ilittlewood22-Nov-15 4:58
professionalilittlewood22-Nov-15 4:58 
AnswerRe: Definition is not quite correct Pin
Gaurav Aroraa22-Nov-15 7:20
professionalGaurav Aroraa22-Nov-15 7:20 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.