Showing posts with label OOP Design Principles in C#. Show all posts
Showing posts with label OOP Design Principles in C#. Show all posts

Sunday, May 10, 2009

The Liskov Substitution Principle in C#.Net (LSP in C#.Net)




The Liskov Substitution principe was coined by Barber Liskov in her work regarding data abstraction and type theory. In simple english the principle can be stated as
“ Any derived class should be substitutable for their base classes”
That is, a user of a base class should continue to function properly if a derivative of that base class is passed to it.
Let us say consider the above example. “SavingsWithDrawform” class has a method which accepts the “Accounts” class object as shown below.
public void WithDraw( Accounts objAcc)
{
//Code Implementation of Account objects
}
The principle of LSP states that it should be legal to pass the the “SavingsAccount” object to the same method, which is as shown
public void WithDraw(SavingsAccounts objAcc)
{
//Passing the derived type should be legal
}

This looks prety obvious. But let us consdier the follwing code example
Let us say we have rectangle class with the following code
public class Rectangle
{
protected int _Height;
protected int _Width;

public int Height
{
get { return _Height; }
}


public int Width
{
get { return _Width; }
}

public virtual void SetHeight(int intHeight)
{
_Height = intHeight;
}
public virtual void SetWidth(int intWidth)
{
_Width = intWidth;
}
}
Now let say we have one more class which is derived from “Rectangle” class is Square class
public class Square:Rectangle
{
public override void SetHeight(int intHeight)
{
_Width = intHeight;
_Height = intHeight;
}
public override void SetWidth(int intWidth)
{
_Height = intWidth;
_Width = intWidth;
} }


Now let say you have a method to calculate area and below is the code for this
Rectangle objRect = new Square();

objRect.SetHeight(2);
objRect.SetWidth(5);

int area = objRect.Width * objRect.Height;

When the area is calcualted it will show as 25, but actually we have expected the value to be 10. So here in this case the derived class is not substitutable for the base class.
References
http://www.objectmentor.com/resources/articles/lsp.pdf

The Open Closed Principle in C# (OCP in C#)



To improve and succeed in market every software needs “Change”. All software change during its life cycle. So it is very important for the developers to design software in a way which can accommodate changes with minimal impact. One of the design principles which help us in designing this kind of software is “Open Closed Principle (OCP)” suggested by Robert Martin. The OCP stats that
“Software entities (Classes, Modules, Functions etc) should be open for extension, but closed for modification”
Software entities that implement the OCP principle will have two big benefits. First they are open to extension which means that we can achieve new business needs with out changing the existing code much. Second they are closed for modification which means that they code itself will not change.
Let us consider an example. Let us say you are designing software for resource allocation. You have two option of resource allocation the “Time slot” and “Space slot”. The below code is implemented without the OCP. The disadvantage with the code is that every time there the new resource type added there need to a lot of changes to the code. Please note the number of comments in below code where the changes are required whenever there is an addition of resource type

Code without OCP


public class ResourceAllocator
{
public string Allocate(int intResourceType)
{
int intRes=0;
switch (intRes)
{
case 1:
return AllocateTimeSlot(intRes); ;
break;
case 2:
return AllocateSpaceSlot(intRes);
break;
//new Case has to be added for a new Allocation Type
default:
throw new Exception("No slot defination");
}
}
public string Free(int intResourceType)
{
int intResFree = 0;
switch (intResFree)
{
case 1:
return FreeTimeSlot(intResFree);
break;
case 2:
return FreeSpaceSlot(intResFree);
break;
//new Case has to be added for a new Allocation Type
default:
throw new Exception("No slot defination");
}
}

//New methods has to be created for the new allocation Type

public string AllocateTimeSlot(int intTimeSlot)
{
//Put the logic to Allocate the time slot
return "";
}
public string AllocateSpaceSlot(int intSpaceSlot)
{
//Put the logic to Allocate the Space slot
return "";
}

public string FreeTimeSlot(int intTimeSlot)
{
//Put the logic to Allocate the Space slot
return "";
}

public string FreeSpaceSlot(int intSpaceSlot)
{
//Put the logic to Allocate the Space slot
return "";
}
}
.
Now let’s take the same example and apply OCP to it.

Below is the code for the resource allocation with OCP

public abstract class ResourcePool
{
public abstract string Allocate(int IntRes);

public abstract string Free(int intRes);

}

public class SpaceSlot:ResourcePool
{

public override string Allocate(int IntRes)
{
//put the logic to allocate space slot
return "";
}

public override string Free(int intRes)
{
//put the logic to free space slot
return "";
}
}

public class TimeSlot : ResourcePool
{
public override string Allocate(int IntRes)
{
//put the logic to allocate time slot
return "";
}

public override string Free(int intRes)
{
//put the logic to Free time slot
return "";
}
}


Now you can have the logic for creating type of object in the resource manager class. Any addition of new code resouce type will not involve much code changes.

Deadly sins of Design (Symptoms of rotting Design)



Every software is designed for a business need. When software is designed it starts with a clear thought process in mind of the developers. At this point the software is in its best shape and in a condition which can be maintained very easily. But there are always changes in business needs and business plans. Your software should be able to meet the business needs and business plans. You start making changes to the code. Slowly you realize that the code is not that maintainable which found earlier and it is not very easy plug new thing into the code. Then your software starts rotting. It continues to a point where it fails completely and you think of re-designing the entire software again. In reality you really get a chance to re-design the entire software and also these re-designs hardly succeeds. So what is the thing which causes the software to rot? Well there are four design symptoms which rots the software if not taken in to consideration from the beginning. They are

• Rigidity
• Fragility
• Immobility
• Viscosity


Rigidity

A software can be called a rigid when it is difficult to change even in a sample way. Every change causes subsequent changes in all the other dependent modules. What begins with a simple two days change in one module grows into changes for weeks as the engineer changes module after module.
Let us consider a defect tracking system. Let us say it is an N-tier architecture product. Let’s say the defect tracking system has a severity dropdown having values like “Critical, Major and Minor”. Now it was decided by the client that there can not be any other values for severity other then “Critical, Major and Minor” The developers have decided to hard cord the values in the UI layer. So every layer has been hard cored with the values and the product has been released to the client. The first release was successful and the client it happy with it.
After a year the client has decided to add “Normal” as one category and remove “Minor” from the category list. The manager felt that this is a simple label change and can be done very easily and has made the commitment accordingly. This has been communicated to the new developer and the developer started looking into the issue. Now the developer realized that since the values have been hardcoded he/she has to go and change each and every layer. Also the developer started exploring all the places where the values have been hard coded. So the commitment to the client can not be met. So what has started with a small change has become an ocean of changes now.
So while designing software it is the responsibility of the architect to make sure that the software is not rigid.


Fragility


Fragility is very closely related with rigidity. Fragility is the tendency of the software to break in many places every time there is change in the software. Often the breakage occurs in areas that has no conceptual link with the changed area. As the fragility of the software increases the chances of breaking increases with time. Such software is difficult to maintain. Every fix that has been introduced will cause more problem than solved.


Immobility


Immobility is the inability to reuse the software from other projects or parts of the same project. This comes when the system engineer finds that the same functionality which needs to be implemented is already available in a different part of the same project or in a different project. However often the modification to make it generic comes with a heavy price. So the engineers decide to re-write the entire code instead of reusing.

Viscosity
Viscosity of software comes in two forms 1. Viscosity of the design 2. Viscosity of environment. Whenever a change is being requested for a software engineers has multiple ways to implement it. Some of the ways preserver the existing design and some do not. Implementing in a way to preserve the design difficult and hence the viscosity is very high. Implementing without preserving the design is very easy and hence has low viscosity.
Viscosity of environment comes when the engineers compromise the design with development environment. For example when the engineers find that the recompiling the entire code takes time, the skip the recompiling of code compromising the design.
The four systems Rigidity, Fragility, Immobility, and Viscosity are the signs of a poor architecture. Software starts rotting after sometime if these points has not been covered properly while designing the software. What causes the software to rot? Well one of the main reasons for the software to rot is change in requirement.