Welcome to the Demystify SOLID article series. In this series we are talking about the SOLID principals of software development. In our previous example we saw two principles of SOLID. I hope you have gone through them and have understood them. Here are links for your reference:
In this article we will discuss the meaning of "L”. L stands for Liskov substitution principal. What does it mean? The Liskov Substitution principal dictates when and where it is correct to derive a subtype from an existing super type. The principal is saying that, a subtype will be completely replaced by a super type.
If the subtype is not completely replaced by a super type then we are not following the Liskov substitution principal completely.
For example, if we derive one class from another parent class then the object of the child class can able to shamelessly by the parent class.
I know it's a little confusing with dry text, let's see an example. Have a look at the following code:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Text;
using System.Threading.Tasks;
namespace EntityFramework
{
public abstract class employee
{
public string employeeName { get; set; }
public abstract void YearlyIncrement();
}
public class parmanentEmployee : employee
{
public override void YearlyIncrement()
{
Console.Write("Increment Done");
}
}
public class temporaryEmployee : employee
{
public override void YearlyIncrement()
{
throw new NotImplementedException("This facility is not for temporary employee");
}
}
class Program
{
static void Main(string[] args)
{
List<employee> empCollection = new List<employee> {
new parmanentEmployee(),
new temporaryEmployee()
};
foreach (employee em in empCollection)
{
em.YearlyIncrement();
}
Console.ReadKey();
}
}
}
And here is the pathetic output.
Why the hell was that done? Let's explain. We created an employee class; that is cool and it is good and is implemented the same for both permanent employee and temporary employee. Now, the YearlyIncrement() function was defined in both functions.
Let's talk business rules. Think that the company dones't have a policy to provide a yearly increment for temporary employees. And to maintain this policy we did not define a body of the YearlyIncrement() function within the temporaryEmployee class.
So if we call the same function then it will throw a not implemented exception. Now, let's get to the Main() function.
Since both of the paramanentEmployee and temporaryEmployee classes are derived from the base employee class we can keep an object of both classes in an employee type collection and we did it.
Now, the year is near to the end and the payroll department will provide a yearly increment, once they start the process, it will throw an error.
Because, as determeind by the business rules, a yearly increment is not applicable to temporary employees. So, we are seeing that the client object is not replacing the base object, hence we are breaking the Liksov substitution principal.
How to solve the problem? Here is the solution.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Text;
using System.Threading.Tasks;
namespace EntityFramework
{
//Employee related function
public interface IEmpFunction
{
void YearlyIncrement();
}
//Base class of all employee
public abstract class employee
{
public string employeeName { get; set; }
}
//parmanent employee
public class parmanentEmployee : employee, IEmpFunction
{
public void YearlyIncrement()
{
Console.Write("Increment Done");
}
}
//Temporary employee
public class temporaryEmployee : employee
{
public override void YearlyIncrement()
{
throw new NotImplementedException("This facility is not for temporary employee");
}
}
class Program
{
static void Main(string[] args)
{
List<employee> empCollection = new List<employee> {
new parmanentEmployee(),
new temporaryEmployee()
};
foreach (employee em in empCollection)
{
em.YearlyIncrement();
}
Console.ReadKey();
}
}
}
We have moved the employee manipulation function to separate interfaces. The employee base class is still there and in the case of a permanent employee class we have implemented an IEmpFunction interface but in the case of the temporaryEmployee class we did not.
Now, when we try to invoke the YearlyIncrement() function using an object of a temporaryEmployee it will complain at compile time, as in the following:
And our problem is solved.
ConclusionI hope the Liksov substitution principal is clear to you. In a future article we will discuss two more principles.
Happy reading happy learning.