Introduction
Let's assume there is type S which get derived from type T
, i.e., type S
is derived type of parent type T
. Type S
contains all [public and protected] functionality of the type T
and it contains more functionality of its own.
E.g. you can use all of you parent’s money and you can have you own money.
Then according to Liskov principle object of type T
may substitute object of type S without altering any of the desirable properties of that program.
E.g. In the financial deal your money may replace by your parent’s money.
Background
Let me start my story.
Man evolution starts and the first man learns to make fire then learns farming and then starts developing factories that start destroying nature by pollution but there are few men that refuse to learn the evolution of destroying nature, they just learn to fire and farming.
Now I want to make a list of all men and show only those who are bad, i.e., they learn pollution.
Let’s start implementing our above mentioned scenario.
We have two abstractions: first is Evolution including the good
evolution: learn to fire and farming, and second abstraction including all the good
evolution plus it has one bad evolution of learning to pollute.
Now consider we have thousands of men out of which a few thousand learn bad evolution as well as good evolution they are of derived type IBadEvolution
and refuse to learn the bad evolution, they just learn the evolution they are of base type IEvolution.
Now we want to build a list of all men that learn Evolution of type IEvolution
.
Then we want to display the list of all men that learn evolution as well as bad evolution from the list of evolution, i.e., substitute IBadEvolution
for IEvolution
.
Using the code
Let's build our base type Evolution abstraction:
public interface IEvolution
{
string Name { get; set; }
void LearnToFire();
void LearnToFarming();
}
Let's build our derived type Bad Evolution as an abstraction, it contains all the evolutions as well as bad evolution.
public interface IBadEvolution : IEvolution
{
void LearToPollution();
}
For simplicity we just consider one man that learns only good evolution, i.e., refuse to learn bad evolution.
public class SomeGoodMan:IEvolution
{
public string Name { get; set; }
public SomeGoodMan()
{
Name = "I am 1st good man ";
}
public void LearnToFire()
{
Console.WriteLine(Name + "learn to fire.");
}
public void LearnToFarming()
{
Console.WriteLine(Name + "learn to farming.");
}
}
We consider two men that learn good evolution as well as bad evolution.
public class BadMan1:IBadEvolution
{
public string Name { get; set; }
public BadMan1()
{
Name ="I am First bad man ";
}
public void LearToPollution()
{
Console.WriteLine(Name + "learn to polution.");
}
public void LearnToFire()
{
Console.WriteLine(Name + "learn to fire.");
}
public void LearnToFarming()
{
Console.WriteLine(Name + "learn to farming.");
}
}
public class BadManN:IBadEvolution
{
public string Name { get; set; }
public BadManN()
{
Name = "I am nth bad man ";
}
public void LearToPollution()
{
Console.WriteLine(Name + "learn to polution.");
}
public void LearnToFire()
{
Console.WriteLine(Name + "learn to fire.");
}
public void LearnToFarming()
{
Console.WriteLine(Name + "learn to farming.");
}
}
Let's build the list of persons that learn evolution and by using substitution principle let's display only those that learn bad evolution.
public class DisplayEvolution
{
static void Main(string[] args)
{
List<IEvolution> evolution = new List<IEvolution>();
evolution.Add(new BadMan1());
evolution.Add(new BadManN());
evolution.Add(new SomeGoodMan());
var listOfBadEvolution = evolution.OfType<IBadEvolution>();
foreach (IBadEvolution badEvolution in listOfBadEvolution)
{
badEvolution.LearnToFire();
badEvolution.LearnToFarming();
badEvolution.LearToPollution();
}
Console.ReadLine();
}
}
So we end up with our simple example of Liskov principle.
Points of Interest
I learned form this exercise that we can avoid the violence of "Liskov Principle" by identifying abstraction in our project.