Pages

Sunday, June 19, 2011

Likov's Substitution Principle with example in C#

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

Saturday, June 18, 2011

Open Closed Principle with real world example in C#

Definition
In object-oriented programming (OOPS), the open closed principle states that software entities (classes, modules, functions, etc.) should be open for extension, but closed for modification


A class should be closed for modifications but their functions or methods can be altered for further open extension


The design should be done in a way to allow the adding of new functionality as new classes, keeping as much as possible existing code unchanged


Now lets see simple real time scenario of Open Closed Principle Violation or Bad Code


Lets consider a simple windows form application of Customer Sales Entity with customer Status as declared with enumeration (Enum)


Enum = Enum stores the constant values.Enums are strongly typed constants.


Customer Name , Customer Code , Product Quantity , Product Rate and with a simple method Calculate Discount
We have Customer Type like Silver, Gold customer which is declared in enum .


For each different customer type we had different discount facility over total amount


Now as you can see we just coded CustomerSalesEntity with set get properties and with Calculate Discount Implementation
 


class ClsCustomerSalesEnity {
public enum CustomerStatus{
Silver,
Gold
}
private string _customername;
private int _customercode;
private int _productquantity;
private double _productrate;
private CustomerStatus _customertype;
public string CustomerName
{
set { _customername = value; }
get { return _customername; }
}
public int CustomerCode
{
set { _customercode = value; }
get { return _customercode; }
}
public CustomerStatus CustomerType
{
set { _customertype = value; }
get { return _customertype; }
}
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 = 0;
if (CustomerType == CustomerStatus.Silver)
{
disrate = 5;
discountamount = (disrate / 100) * rate;
rate = rate - discountamount;
}
if (CustomerType == CustomerStatus.Gold)
{
disrate = 20;
discountamount = (disrate / 100) * rate;
rate = rate - discountamount;
}
return rate;
}
}


As per code when you at the CalculateDiscountRate() method there we distinguish customer type (Silver,Gold) discount rate with if condition
 


Sample
public enum CustomerStatus
{
Silver,
Gold
}
If (CustomerType == CustomerStatus.Silver {
disrate = 5;
discountamount = (disrate / 100) * rate;
rate = rate - discountamount;
}
if (CustomerType == CustomerStatus.Gold)
{
disrate = 20;
discountamount = (disrate / 100) * rate;
rate = rate - discountamount;
}
 


This code looks perfect we create dll and ship this application as per our client requirement


Then you must me thinking what the problem was?


The problem is that consider that our Client wants add new category or new customer type (Customer Bronze) then we might need to modify existing class and where ever we use this class everywhere we to need to modifications simply means just to modify a full application then deploy again. Again and again for any Clients changes we need to modify existing code / class


The Code was not designed properly here where OCP violates


Just Testing Purpose


On Windows form.cs on button click just add this code
ClsCustomerSalesEnity objCustomerEntity = new ClsCustomerSalesEnity();
objCustomerEntity.CustomerCode = Convert.ToInt16(textBox1.Text);
objCustomerEntity.CustomerName = textBox2.Text;
objCustomerEntity.CustomerType = (ClsCustomerSalesEnity.CustomerStatus)Enum.Parse(typeof(ClsCustomerSalesEnity.CustomerStatus), textBox3.Text, true);
;
objCustomerEntity.ProductQuantity = Convert.ToInt16(textBox4.Text);
objCustomerEntity.ProductRate = Convert.ToDouble(textBox5.Text);
label7.Text = Convert.ToString(objCustomerEntity.CalculateDiscountRate());
 
 
 


Now let’s see solutions for above Code
Now we need to make our CutomerSalesEntity flexible so that It  cannot be modified further but can open for an extension
 


Step 1
We give abstract keyword to our CutomerSalesEntity class


Step 2
Method or property which we think or designed in that way to be altered in future or can be flexible for extension  (Need to be keep abstract or virtual )
 


Here I will give abstract keyword to method CalculateDiscountRate()
 


Now lets see the following code
public abstract class ClsCustomerSalesEnity
{
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 abstract double CalculateDiscountRate();
}
 


This is our Fix CustomerSalesEntity class which in further now going to be modified but yes will be open for extension
 


Now assume that we want to add new customer Type (say gold customer)


For that we will be creating new class clsGoldCustomerSalesEntity and inheriting from


ClsCustomerSalesEnity


public class clsGoldCustomerSalesEntity : ClsCustomerSalesEnity
{
public override double CalculateDiscountRate()
{
double rate = ProductQuantity * ProductRate;
double discountamount = 0;
double disrate = 20;
discountamount = (disrate / 100) * rate;
rate = rate - discountamount;
return rate;
}
}
 


Again if want to add new customer we will be doing same procedure
 


public class clsSilverSalesEntity : ClsAbstractCustomerSalesEnity
{
public override double CalculateDiscountRate()
{
double rate = ProductQuantity * ProductRate;
double discountamount = 0;
double disrate = 5;
discountamount = (disrate / 100) * rate;
rate = rate - discountamount;
return rate;
}
}
 


So as you can see that Our CustomerSalesEntity class is open for extension but closed for modification
Here OCP rules fulfills solution