Suggested Videos
Single Responsibility Principle | Text | Slides
Interface Segregation Principle | Text | Slides
Open Closed Principle | Text | Slides
In this video we will learn
In the first video of SOLID Introduction we have understood that L in the SOLID is acronym for Liskov Substitution Principle which is also known as LSP.
Definition : Substitutability is a principle in object-oriented programming and it states that, in a computer program, if S is a Subtype of T, then objects of type T may be replaced with objects of type S
Implementation guidelines : In the process of development we should ensure that
Now if you take a look at the main program, we have created Employee objects which consists of both permanent and contract employee.
If you take a closer look at this program the Derived types which are Permanent and TemporaryEmployee have completely substituted the base type employee class.
So, based on the Liskov substitution principle we have achieved LSP by ensuring that Derived types are completely substitutable for their base types.
Also, notice the main program, without using the subtypes we are calculating the bonus of the employee from the base class type itself. Hence, we are satisfying the Liskov substitution principle.
That means along with the Open Closed Principle we have partially implemented the LSP.
Also, I can state that this implementation is not adhering to guide lines of Liskov principle
To understand why it’s not adhering to the Liskov Principle, Let’s assume that we need to have a Contract Employee as one of the employee category. A point to note here is a contract employee is not eligible for any bonus calculation and post implementing the Employee class we end up throwing exception at the runtime in the caclculatebonus() method. This violates the Liskov Substitution Principle.
Hence, Please follow the below code which addresses this issue. Also, we recommend to watch our video tutorials for complete guidance and understanding of the code.
Code before Liskov Substitution Principle.
We strongly recommend you to refer to our design patterns tutorial for more details on creational design patterns
I believe this video has given you a good idea on how we can implement Liskov substitution principle
In our next video we will discuss Dependency Inversion Principle.
Single Responsibility Principle | Text | Slides
Interface Segregation Principle | Text | Slides
Open Closed Principle | Text | Slides
In this video we will learn
- Liskov Substitution Principle
- Implementation guidelines of Liskov Substitution Principle
- And will implement this Principle with a simple example
In the first video of SOLID Introduction we have understood that L in the SOLID is acronym for Liskov Substitution Principle which is also known as LSP.
Definition : Substitutability is a principle in object-oriented programming and it states that, in a computer program, if S is a Subtype of T, then objects of type T may be replaced with objects of type S
- Which means, Derived types must be completely substitutable for their base types
- More formally, the Liskov substitution principle (LSP) is a particular definition of a subtyping relation, called (strong) behavioral subtyping
- This Principle is introduced by Barbara Liskov in 1987 during her conference address on Data abstraction and hierarchy
- This principle is just an extension of the Open Close Principle
Implementation guidelines : In the process of development we should ensure that
- No new exceptions can be thrown by the subtype unless they are part of the existing exception hierarchy.
- We should also ensure that Clients should not know which specific subtype they are calling, nor should they need to know that. The client should behave the same regardless of the subtype instance that it is given.
- And last but not the least, New derived classes just extend without replacing the functionality of old classes
Now if you take a look at the main program, we have created Employee objects which consists of both permanent and contract employee.
If you take a closer look at this program the Derived types which are Permanent and TemporaryEmployee have completely substituted the base type employee class.
So, based on the Liskov substitution principle we have achieved LSP by ensuring that Derived types are completely substitutable for their base types.
Also, notice the main program, without using the subtypes we are calculating the bonus of the employee from the base class type itself. Hence, we are satisfying the Liskov substitution principle.
That means along with the Open Closed Principle we have partially implemented the LSP.
Also, I can state that this implementation is not adhering to guide lines of Liskov principle
To understand why it’s not adhering to the Liskov Principle, Let’s assume that we need to have a Contract Employee as one of the employee category. A point to note here is a contract employee is not eligible for any bonus calculation and post implementing the Employee class we end up throwing exception at the runtime in the caclculatebonus() method. This violates the Liskov Substitution Principle.
Hence, Please follow the below code which addresses this issue. Also, we recommend to watch our video tutorials for complete guidance and understanding of the code.
Code before Liskov Substitution Principle.
using System;
using
System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace OpenClosedDemo
{
public abstract class Employee
{
public int ID { get; set; }
public string Name { get; set; }
public Employee()
{
}
public Employee(int id, string name )
{
this.ID = id; this.Name =
name;
}
public abstract decimal
CalculateBonus(decimal salary);
public override string ToString()
{
return string.Format("ID : {0} Name : {1}", this.ID, this.Name);
}
}
public class PermanentEmployee : Employee
{
public
PermanentEmployee()
{ }
public
PermanentEmployee(int id, string name) : base(id, name)
{ }
public override decimal
CalculateBonus(decimal salary)
{
return salary * .1M;
}
}
public class TemporaryEmployee : Employee
{
public
TemporaryEmployee()
{ }
public
TemporaryEmployee(int id, string name) : base(id, name)
{ }
public override decimal
CalculateBonus(decimal salary)
{
return salary * .05M;
}
}
public class ContractEmployee : Employee
{
public
ContractEmployee()
{ }
public
ContractEmployee(int id, string name) : base(id, name)
{ }
public override decimal
CalculateBonus(decimal salary)
{
throw new NotImplementedException();
}
}
}
using System;
using
System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace OpenClosedDemo
{
class Program
{
static void Main(string[] args)
{
Employee empJohn
= new PermanentEmployee(1, "John" );
Employee
empJason = new TemporaryEmployee(2, "Jason" );
Employee empMike
= new ContractEmployee(3, "Mike" );
Console.WriteLine(string.Format("Employee
{0} Bonus: {1}",
empJohn.ToString(),
empJohn.CalculateBonus(100000).ToString()));
Console.WriteLine(string.Format("Employee
{0} Bonus: {1}",
empJason.ToString(),
empJason.CalculateBonus(150000).ToString()));
Console.WriteLine(string.Format("Employee
{0} Bonus: {1}",
empMike.ToString(),
empMike.CalculateBonus(150000).ToString()));
Console.ReadLine();
}
}
}
Above code throws an error at
empMike, as Bonus is not applicable to ContractEmployee. In that case LSP is
violated and we have redefined the code to follow LSP below.
Code after Implementing Liskov
Substitution Principle.
using System;
using
System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace LSPDemoConsole
{
interface IEmployee
{
int ID { get; set; }
string Name { get; set; }
decimal
GetMinimumSalary();
}
}
using System;
using
System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace LSPDemoConsole
{
interface IEmployeeBonus
{
decimal
CalculateBonus(decimal salary);
}
}
using System;
using
System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace LSPDemoConsole
{
public abstract class Employee : IEmployee,
IEmployeeBonus
{
public int ID { get; set; }
public string Name { get; set; }
public Employee()
{ }
public Employee(int id, string name)
{
this.ID = id;
this.Name = name;
}
public abstract decimal
CalculateBonus(decimal salary);
public override string ToString()
{
return string.Format("ID : {0} Name : {1}", this.ID, this.Name);
}
public abstract decimal
GetMinimumSalary();
}
}
using System;
using
System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace
LSPDemoConsole.Implementation
{
public class PermanentEmployee : Employee
{
public
PermanentEmployee()
{ }
public
PermanentEmployee(int id, string name) : base(id, name)
{ }
public override decimal
CalculateBonus(decimal salary)
{
return (salary *
.1M);
}
public override decimal
GetMinimumSalary()
{
return 15000;
}
}
}
using System;
using
System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace
LSPDemoConsole.Implementation
{
public class TemporaryEmployee : Employee
{
public
TemporaryEmployee()
{ }
public
TemporaryEmployee(int id, string name) : base(id, name)
{ }
public override decimal
CalculateBonus(decimal salary)
{
return (salary *
.05M);
}
public override decimal
GetMinimumSalary()
{
return 5000;
}
}
}
using System;
using
System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace
LSPDemoConsole.Implementation
{
public class ContractEmployee : IEmployee
{
public int ID { get; set; }
public string Name { get; set; }
public
ContractEmployee()
{ }
public
ContractEmployee(int id, string name)
{
this.ID = id;
this.Name = name;
}
public decimal
GetMinimumSalary()
{
return 5000;
}
public override string ToString()
{
return string.Format("ID : {0} Name : {1}", this.ID, this.Name);
}
}
}
using
LSPDemoConsole.Implementation;
using System;
using
System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace LSPDemoConsole
{
class Program
{
static void Main(string[] args)
{
List<Employee> employees = new List<Employee>();
employees.Add(new
PermanentEmployee(1, "John"));
employees.Add(new
TemporaryEmployee(2, "Jason"));
//Un Comment to see the error
//employees.Add(new ContractEmployee(3,
"Mike"));
foreach (var employee in employees)
{
Console.WriteLine(string.Format("Employee
{0} Bonus: {1} MinSalary: {2}",
employee.ToString(),
employee.CalculateBonus(100000).ToString(),
employee.GetMinimumSalary().ToString()));
}
Console.WriteLine();
List
<IEmployee> employeesOnly = new List<IEmployee>();
employeesOnly.Add(new PermanentEmployee(1, "John"));
employeesOnly.Add(new TemporaryEmployee(2, "Jason"));
employeesOnly.Add(new ContractEmployee(3, "Mike"));
foreach (var employee in employeesOnly)
{
Console.WriteLine(string.Format("Employee
{0} MinSalary: {1}",
employee.ToString(),
employee.GetMinimumSalary().ToString()));
}
Console.ReadLine();
}
}
}
We strongly recommend you to refer to our design patterns tutorial for more details on creational design patterns
I believe this video has given you a good idea on how we can implement Liskov substitution principle
In our next video we will discuss Dependency Inversion Principle.
Awesom!!! Thank you very much for this article.
ReplyDeleteBut using IEmployee type list we are not able to access CalculateBonus() method for Permanent and Temporary employee. Then what is the use of creating IEmployee type list? If we need to create 2 type of list Employee Type and IEmployee type every time then i guess its not adhering to LISKOV principle. Please correct me if i am wrong. Also anyone else please give proper solution. Thanks..!!
ReplyDelete