Definition
Likov's Substitution Principle states that if for each object m1 of type S there is an object m2 of type T such that for all programs P defined in terms of T, the behavior of P is unchanged when m1 is substituted for m2 then S is a subtype of T.
Now let’s see the simple example of LSP Violation of code
In this example we have one common interface “ICustomer” which is inherits to two classes i.e.
ClsPaidCustomerSalesEnity, ClsFreeCustomerSalesEnity . two different classes which set and get properties and do calculation and print invoice as per customer status
For ClsPaidCustomerSalesEnity we have calculated special discount and printed the Invoice with customer name and amount
For ClsFreeCustomerSalesEnity we have 0 discount and in PrintInvoice we return something
throw new NotImplementedException();
Means nothing was implemented in this method
//Interface Code
public interface ICustomer
{
string CustomerName { set; get; }
int CustomerCode { set; get; }
int ProductQuantity { set; get; }
double ProductRate { set; get; }
double CalculateDiscountRate();
string PrintInvoice(double _amount);
}
//Paid Customer Code
public class ClsPaidCustomerSalesEnity : ICustomer
{
private string _customername;
private int _customercode;
private int _productquantity;
private double _productrate;
public string CustomerName
{
set { _customername = value; }
get { return _customername; }
}
public int CustomerCode
{
set { _customercode = value; }
get { return _customercode; }
}
public int ProductQuantity
{
set { _productquantity = value; }
get { return _productquantity; }
}
public double ProductRate
{
set { _productrate = value; }
get { return _productrate; }
}
public double CalculateDiscountRate()
{
double rate = ProductQuantity * ProductRate;
double discountamount = 0;
double disrate = 20;
discountamount = (disrate / 100) * rate;
rate = rate - discountamount;
return rate;
}
public string PrintInvoice(double _amount)
{
return "Product Invoice For Customer " + CustomerName + " with Total Amount " + _amount;
}
}
//Free Customer Code
public class ClsFreeCustomerSalesEnity : ICustomer
{
private string _customername;
private int _customercode;
private int _productquantity;
private double _productrate;
public string CustomerName
{
set { _customername = value; }
get { return _customername; }
}
public int CustomerCode
{
set { _customercode = value; }
get { return _customercode; }
}
public int ProductQuantity
{
set { _productquantity = value; }
get { return _productquantity; }
}
public double ProductRate
{
set { _productrate = value; }
get { return _productrate; }
}
public double CalculateDiscountRate()
{
return 0;
}
public string PrintInvoice(double _amount)
{
throw new NotImplementedException();
}
}
Both code is almost similar but only difference in implementation and inherits with common interface
Now let’s come to our window form application code
ICustomer objIcust;
List listcust = new List();
objIcust = new ClsPaidCustomerSalesEnity();
objIcust.CustomerName = "Paid Customer";
objIcust.CustomerCode = 001;
objIcust.ProductQuantity = 5;
objIcust.ProductRate = 20;
listcust.Add(objIcust);
objIcust = new ClsFreeCustomerSalesEnity();
objIcust.CustomerName = "Free Customer";
objIcust.CustomerCode = 002;
objIcust.ProductQuantity = 5;
objIcust.ProductRate = 20;
listcust.Add(objIcust);
string printinvoice = "";
foreach (ICustomer iCust in listcust)
{
double amount = iCust.CalculateDiscountRate();
printinvoice = iCust.PrintInvoice(amount);
listBox1.Items.Add("Invoice Report --> " + printinvoice);
}
Problem with this code when loop our Icustomer collections it will work fine with
ClsPaidCustomerSalesEnity calculates Discount Rate and and print invoice properly
But when it loads ClsFreeCustomerSalesEnity CalculateDiscountRate returns 0 and for PrintInvoice it throws new NotImplemented Exception which is totally wrong and on UI we don’t need any exception error and writing Hacks and like if conditions is not proper way of design architecture
This is the problem with code
As it says it Free Customer code like paid customer code but unlike paid customer code there is not implementation of DiscountRate and Print Invoice method
So now let’s see the solution for above code using Likov's Substitution Principle
A simple solutions but Customer Type i.e. paid customer class and free customer are not same difference in discount rate and print invoice implementation
If it looks like a duck, quacks like a duck, but needs batteries - wrong abstraction
So we need to create different interface for paid customer and for free customer
public interface IFreeCustomer
{
string CustomerName { set; get; }
int CustomerCode { set; get; }
int ProductQuantity { set; get; }
double ProductRate { set; get; }
}
//use this for paid customer for printing invoice
public interface IPaidPrintCustomer
{
string CustomerName { set; get; }
int CustomerCode { set; get; }
int ProductQuantity { set; get; }
double ProductRate { set; get; }
double CalculateDiscountRate();
string PrintInvoice(double _amount);
}
public class ClsPaidCustomerSalesEnity : IPaidPrintCustomer
{
//do the implementation as same as we did for customer
}
public class ClsFreeCustomerSalesEnity : IFreeCustomer
{
//do the implementation as same as we did for customer
}
Then create separate objects and call it in UI
So Problem is solved successfully
Likov's Substitution Principle states that if for each object m1 of type S there is an object m2 of type T such that for all programs P defined in terms of T, the behavior of P is unchanged when m1 is substituted for m2 then S is a subtype of T.
Now let’s see the simple example of LSP Violation of code
In this example we have one common interface “ICustomer” which is inherits to two classes i.e.
ClsPaidCustomerSalesEnity, ClsFreeCustomerSalesEnity . two different classes which set and get properties and do calculation and print invoice as per customer status
For ClsPaidCustomerSalesEnity we have calculated special discount and printed the Invoice with customer name and amount
For ClsFreeCustomerSalesEnity we have 0 discount and in PrintInvoice we return something
throw new NotImplementedException();
Means nothing was implemented in this method
//Interface Code
public interface ICustomer
{
string CustomerName { set; get; }
int CustomerCode { set; get; }
int ProductQuantity { set; get; }
double ProductRate { set; get; }
double CalculateDiscountRate();
string PrintInvoice(double _amount);
}
//Paid Customer Code
public class ClsPaidCustomerSalesEnity : ICustomer
{
private string _customername;
private int _customercode;
private int _productquantity;
private double _productrate;
public string CustomerName
{
set { _customername = value; }
get { return _customername; }
}
public int CustomerCode
{
set { _customercode = value; }
get { return _customercode; }
}
public int ProductQuantity
{
set { _productquantity = value; }
get { return _productquantity; }
}
public double ProductRate
{
set { _productrate = value; }
get { return _productrate; }
}
public double CalculateDiscountRate()
{
double rate = ProductQuantity * ProductRate;
double discountamount = 0;
double disrate = 20;
discountamount = (disrate / 100) * rate;
rate = rate - discountamount;
return rate;
}
public string PrintInvoice(double _amount)
{
return "Product Invoice For Customer " + CustomerName + " with Total Amount " + _amount;
}
}
//Free Customer Code
public class ClsFreeCustomerSalesEnity : ICustomer
{
private string _customername;
private int _customercode;
private int _productquantity;
private double _productrate;
public string CustomerName
{
set { _customername = value; }
get { return _customername; }
}
public int CustomerCode
{
set { _customercode = value; }
get { return _customercode; }
}
public int ProductQuantity
{
set { _productquantity = value; }
get { return _productquantity; }
}
public double ProductRate
{
set { _productrate = value; }
get { return _productrate; }
}
public double CalculateDiscountRate()
{
return 0;
}
public string PrintInvoice(double _amount)
{
throw new NotImplementedException();
}
}
Both code is almost similar but only difference in implementation and inherits with common interface
Now let’s come to our window form application code
ICustomer objIcust;
List
objIcust = new ClsPaidCustomerSalesEnity();
objIcust.CustomerName = "Paid Customer";
objIcust.CustomerCode = 001;
objIcust.ProductQuantity = 5;
objIcust.ProductRate = 20;
listcust.Add(objIcust);
objIcust = new ClsFreeCustomerSalesEnity();
objIcust.CustomerName = "Free Customer";
objIcust.CustomerCode = 002;
objIcust.ProductQuantity = 5;
objIcust.ProductRate = 20;
listcust.Add(objIcust);
string printinvoice = "";
foreach (ICustomer iCust in listcust)
{
double amount = iCust.CalculateDiscountRate();
printinvoice = iCust.PrintInvoice(amount);
listBox1.Items.Add("Invoice Report --> " + printinvoice);
}
Problem with this code when loop our Icustomer collections it will work fine with
ClsPaidCustomerSalesEnity calculates Discount Rate and and print invoice properly
But when it loads ClsFreeCustomerSalesEnity CalculateDiscountRate returns 0 and for PrintInvoice it throws new NotImplemented Exception which is totally wrong and on UI we don’t need any exception error and writing Hacks and like if conditions is not proper way of design architecture
This is the problem with code
As it says it Free Customer code like paid customer code but unlike paid customer code there is not implementation of DiscountRate and Print Invoice method
So now let’s see the solution for above code using Likov's Substitution Principle
A simple solutions but Customer Type i.e. paid customer class and free customer are not same difference in discount rate and print invoice implementation
If it looks like a duck, quacks like a duck, but needs batteries - wrong abstraction
So we need to create different interface for paid customer and for free customer
public interface IFreeCustomer
{
string CustomerName { set; get; }
int CustomerCode { set; get; }
int ProductQuantity { set; get; }
double ProductRate { set; get; }
}
//use this for paid customer for printing invoice
public interface IPaidPrintCustomer
{
string CustomerName { set; get; }
int CustomerCode { set; get; }
int ProductQuantity { set; get; }
double ProductRate { set; get; }
double CalculateDiscountRate();
string PrintInvoice(double _amount);
}
public class ClsPaidCustomerSalesEnity : IPaidPrintCustomer
{
//do the implementation as same as we did for customer
}
public class ClsFreeCustomerSalesEnity : IFreeCustomer
{
//do the implementation as same as we did for customer
}
Then create separate objects and call it in UI
So Problem is solved successfully