Click here to Skip to main content
15,499,801 members
Articles / Programming Languages / C#
Technical Blog
Posted 22 Nov 2015

Tagged as

Stats

5.6K views
5 bookmarked

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
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
Architect
India India
There is no age limit for learning and its never late, to start.

Comments and Discussions

 
QuestionLinks are b0rked Pin
Member 1140848924-Nov-15 0:42
MemberMember 1140848924-Nov-15 0:42 
QuestionDefinition is not quite correct Pin
ilittlewood22-Nov-15 5:58
professionalilittlewood22-Nov-15 5:58 
AnswerRe: Definition is not quite correct Pin
Gaurav Aroraa22-Nov-15 8:20
professionalGaurav Aroraa22-Nov-15 8:20 
Its nice to hear and thanks for making it correct, I will update the definition sooner. The query regarding code violation - please download complete project from Github repo and you can see, how and why the mentioned code-snippet is there.
Gaurav Arora
http://gaurav-arora.com

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.