SOLID are five basic principles which help to create good
software architecture. SOLID is an acronym where:-
- S stands for SRP (Single responsibility principle)
- O stands for OCP (Open closed principle)
- L stands for LSP (Liskov substitution principle)
- I stands for ISP ( Interface segregation principle)
- D stands for DIP ( Dependency inversion principle)
“S”- Single responsibility principle
Meaning: An object should only have one reason to change;
the longer the file or class; the more difficult it will be to achieve this.
Have a look at the code below, can you guess what the
problem is?
class Customer
{
public void Add()
{
try
{
// Database code goes here
}
catch (Exception ex)
{
System.IO.File.WriteAllText(@"c:\Error.txt",
ex.ToString());
}
}
}
The above customer class is doing things WHICH HE IS
NOT SUPPOSED TO DO. Customer class should do customer data validations, call
the customer data access layer etc , but if you see the catch block closely it
also doing LOGGING activity. In simple words its over loaded with lot of responsibility.
So tomorrow if add a new logger like event viewer I need to go and change the
“Customer”class, that’s very ODD.
“O” - Open closed principle
Meaning: Software entities (classes, modules, functions,
etc.) should be open for extension, but closed for modification.
Let’s continue with our same customer class example. I have
added a simple customer type property to the class. This property decided if
this is a “Gold” or “Silver” customer.
Depending on the same it calculates discount. Have a look at
the “getDiscount” function which returns discount accordingly. 1 for Gold
customer and 2 for Silver customer.
class Customer
{
private int _CustType;
public int CustType
{
get { return _CustType; }
set { _CustType = value; }
}
public double getDiscount(double TotalSales)
{
if (_CustType == 1)
{
return TotalSales - 100;
}
else
{
return TotalSales - 50;
}
}
}
The problem is if we add a new customer type we need to go
and add one more “IF” condition in the “getDiscount” function, in other words
we need to change the customer class.
How about rather than “MODIFYING” we go for “EXTENSION”. In
other words every time a new customer type needs to be added we create a new
class as shown in the below. So whatever is the current code they are untouched
and we just need to test and check the new classes.
“L”- Liskov substitution principle
Meaning: If S is a subtype of T, then objects of type T may
be replaced with objects of type S (in other words, objects of type S may
substitute objects of type T) without altering any of the desirable properties
of that program (correctness, task performed, and so on).
public class Rectangle
{
protected int _width;
protected int _height;
public int Width
{
get { return _width; }
}
public int Height
{
get { return _height; }
}
public virtual void SetWidth(int width)
{
_width = width;
}
public virtual void SetHeight(int height)
{
_height = height;
}
public int getArea()
{
return _width * _height;
}
}
public class Square : Rectangle // In an "is a" relationship, the
derived class is clearly a
//kind of the base class
{
public override void SetWidth(int width)
{
_width = width;
_height = width;
}
public override void SetHeight(int height)
{
_height = height;
_width = height;
}
}
public void AreaOfRectangle()
{
Rectangle r = RectangleFactory(); // Returns the rectangle
type object
r.SetWidth(7);
r.SetHeight(3);
r.getArea();
}
So can you tell me the out put of the r.getArea();
method . Yes very simple the expected output is
public Rectangle
RectangleFactory()
{
return new Square();
}
One thing i want to mention about the RectangleFactory() is
that , this method is now exposed to you. But think as if you are getting the Rectangle object
just by using a factory dll or from any service where you have no idea what
type of rectangle object will be return.
So what’s wrong there? Remember as I said earlier
Now the solution is to manage the class inheritance hierarchies
correctly. Let’s introduce another class
public class Quadrilaterals
{
public virtual int Height { get; set; }
public virtual int Width { get; set; }
public int getArea()
{
return Height * Width;
}
}
public class Rectangle :Quadrilaterals
{
public override int Width
{
get { return base.Width; }
set { base.Width = value; }
}
public override int Height
{
get { return base.Height; }
set { base.Height = value; }
}
}
public class Square : Quadrilaterals // In an "is a" relationship, the
derived class is clearly a
//kind of the base class
{
public override int Height
{
get { return base.Height; }
set { SetWidthAndHeight(value); }
}
public override int Width
{
get { return base.Width; }
set { SetWidthAndHeight(value); }
}
private void SetWidthAndHeight(int value)
{
base.Height = value;
base.Width = value;
}
}
“I” - Interface Segregation principle
Meaning: The principle states that no client should be
forced to depend on methods that it does not use
Now assume that our customer class has become a SUPER HIT
component and it’s consumed across 1000 clients and they are very happy using
the customer class.
Now let’s say some new clients come up with a demand saying
that we also want a method which will help us to “Read” customer data. So
developers who are highly enthusiastic would like to change the “IDatabase”
interfaceas shown below.
interface IDatabase
{
void Add(); // old client are happy with these.
voidRead(); // Added for new clients.
}
Now by changing the current interface you are doing an awful
thing, disturbing the 1000 satisfied current client’s , even when they are not
interested in the “Read” method. You are forcing them to use the “Read” method.
So the better solution would be to create a new interface rather
than updating the current interface. So we can keep the current interface
“IDatabase” as it is and add a new interface “IDatabaseV1” with the “Read”
method the “V1” stands for version 1.
interface IDatabaseV1 : IDatabase // Gets the Add method
{
Void Read();
}
“D”- Dependency inversion principle
Meaning:
- High-level modules should not depend on low-level modules. Both should depend on abstractions.
- Abstractions should not depend on details. Details should depend on abstractions.
About the author:
Akash Singh Verma is a consultant in Systems Plus Pvt. Ltd. Within Systems Plus, he actively contributes to the areas of Technology and Information Security. He can be contacted at akash.v@spluspl.com
Nice Blog.....
ReplyDeleteInformative BLog
ReplyDeletegood info
ReplyDeleteNice one
ReplyDeleteVery informative best IT networking company in dubai
ReplyDelete