SOLID Architectural Pattern With Real Time Example: Single Responsibility Principle (SRP)
SOLID Architectural Pattern With Real Time Example: Single Responsibility Principle (SRP)
In interview interviewer often asked real time example of SOLID design pattern. So I decide to
write some real time example of SOLID design pattern.
What is SOLID?
SOLID is an acronym for five principle of architecture.
Example - Suppose you have created a class XmlValidator for xml validation which has the
responsibility to validate the xml.
If there is a need to update the xml than a separate class should be created for the same.
XmlValidator class should not be use for updating the xml.
Example – Suppose we class name Customer which has a property InvoiceNumber which has
integer type
}
}
And in future requirement has been changed now InvoiceNumber should be alphanumeric
rather than only integer. So in this case you should create a subclass CustomerNew with a same
property but different datatype rather than modifying previous one.
}
}
Liskov Substitution Principle (LSP)–
A parent object should be able to replace its child during runtime polymorphism.
Example - Suppose you have two classes Cooler and Fan, both are inherited from a common
interface named ISwitch. Which has three methods On, Off and Regulate.
}
public void Off()
{
}
public void Regulate()
{
Everything was fine until a new class introduced for same interface named Bulb which have
only two methods On and Off. It does not have Regulate method. So Bulb class is
}
public void Regulate()
{
throw new NotImplementedException();
}
if(o is Bulb)
continue;
o.Regulate();
}
This is an example of bad design, if above condition used somewhere it clearly means
that there is violation of LSK principle.
As time passes new requirement comes for adding one more function onLongClick. And you
add this method in already created interface
After some time one new requirement comes for adding function for touch also and you add
the method in same interface
At this point you decide to change the name of interface too because touch if different than
click.
And this way this interface becoming a problem—generic and polluted. So at this stage ISP
comes in light.
ITouch and IClick. The client which has required onClick, it can implement IClick and which need
onTouch it can implement ITouch and which need both, it can implement both.
In other words no object should be created inside a class they should be passed or injected from
outside. And where it would receive it will be an interface rather class.
class Student
{
// Handle to EventLog writer to write to the logs
LogWriter writer = null;
// This function will be called when the student has problem
public void Notify(string message)
{
if (writer == null)
{
writer = new LogWriter();
}
writer.Write(message);
}
}
class Student
{
// Handle to EventLog writer to write to the logs
LogWriter writer = null;
Public Student(LogWriter writer)
{
This.writer = writer;
}
// This function will be called when the student has problem
public void Notify(string message)
{
writer.Write(message);
}
}
Above written classes are bad designs because in case of in change in LogWrite, you have to
disturb Student class. We should use interface inside Student instead of class.
This.writer = writer;
}
// This function will be called when the student has problem
public void Notify(string message)
{
writer.Write(message);
}
}
//////////////////////////////////////////////////////////////////////////////
<h2>SOLID Architectural</h2>
<p>In interview interviewer often asked real time example of SOLID design pattern. So I
decided to write some real time example of SOLID design pattern.</p>
<h2>What is SOLID?</h2>
<p>It says that every class should have single responsibility. A class should not have more than
one reason to change. Example - Suppose you have created a class XmlValidator for xml
validation which has the responsibility to validate the xml. If there is a need to update the xml
than a separate class should be created for the same. XmlValidator class should not be use for
updating the xml.</p>
<p>Wrong design</p>
<p>Here XML validator class used for both validating and updating which is wrong.</p>
<pre lang="C++">
public class XmlValidator
{
</pre>
<p>For updating, a new class should be created. Here is the right design.</p>
<pre lang="C++">
public class XmlValidator
{
public void Validate()
{
//Code
}
}
</pre>
<h2>Open Close Principle (OCP)–</h2>
<p>Example – Suppose we have class name Customer which has a property
InvoiceNumber which has integer type.</p>
<pre lang="C++">
public class Customer
{
public int InvoiceNumber
{
get;
set;
}
}
</pre>
<p>And in future requirement has been changed now InvoiceNumber should be alphanumeric
rather than only integer. So in this case you should create a subclass CustomerNew with same
property but different datatype rather than modifying previous one.</p>
<pre lang="C++">
public class CustomerNew : Customer
{
public new String InvoiceNumber
{
get;
set;
}
}
</pre>
<p>A parent object should be able to replace its child during runtime polymorphism. Example -
Suppose you have two classes Cooler and Fan, both are inherited from a common interface
named ISwitch. Which has three methods On, Off and Regulate.</p>
<pre lang="C++">
public interface ISwitch
{
void On();
void Off();
void Regulate();
}
}
public void Off()
{
}
}
}
public void Regulate()
{
</pre>
<p>Everything was fine until a new class introduced for same interface named Bulb which have
only two methods On and Off. It does not have Regulate method. So Bulb class is</p>
<pre lang="C++">
}
public void Regulate()
{
throw new NotImplementedException();
}
</pre>
<pre lang="C++">
public void AddObject()
{
List<ISwitch> Switch = new List<ISwitch>();
Switch.Add(new Cooler());
Switch.Add(new Fan());
Switch.Add(new Bulb());
<p>In this case Regulate method will throw an error.One horrible solution to this problem is, put
an if condition.</p>
<pre lang="C++">
foreach (var o in Switch)
{
if(o is Bulb)
continue;
o.Regulate();
}
</pre>
<p>This is an example of bad design, if above condition used somewhere it clearly means that
there is violation of LSK principle.</p>
<p>Client specific interfaces are better than one general purpose interfaces. Suppose we have
one interface for click</p>
<pre lang="C++">
<p>As time passes new requirement comes for adding one more function onLongClick. And you
add this method in already created interface.</p>
<pre lang="C++">
<p>After some time one new requirement comes for adding function for touch also and you add
the method in same interface.</p>
<pre lang="C++">
<p>At this point you decide to change the name of interface too because touch is different than
click. And this way this interface becoming a problem, generic and polluted. So at this stage ISP
comes in light.</p>
<p>Suppose some clients need only onClick function and some need only onTouch function than
one will be useless for both. So ISP gives the solution, split the interface into two interfaces
ITouch and IClick. The client which has required onClick, it can implement IClick and which
need onTouch it can implement ITouch and which need both, it can implement both.</p>
<pre lang="C++">
public interface IClick
{
void onClick(Object obj);
void onLongClick(Object obj);
}
</pre>
<p>It states two points, first point is higher level module should not depend on low level
module. Both should depend on abstraction. And second point is, Abstraction should not depend
detail. Detail should depend on abstraction. In other words no object should be created inside a
class, they should be passed or injected from outside. And where it would receive it will be an
interface rather class. Here is a bad design without using dependency injection.</p>
<pre lang="C++">
class Student
{
// Handle to EventLog writer to write to the logs
LogWriter writer = null;
// This function will be called when the student has problem
public void Notify(string message)
{
if (writer == null)
{
writer = new LogWriter();
}
writer.Write(message);
}
}
</pre>
<pre lang="C++">
class Student
{
// Handle to EventLog writer to write to the logs
LogWriter writer = null;
Public Student(LogWriter writer)
{
This.writer = writer;
}
// This function will be called when the student has problem
public void Notify(string message)
{
writer.Write(message);
}
}
</pre>
<p>Above written classes are bad designs because in case of any change in LogWrite, you have
to disturb Student class. We should use an interface inside Student instead of class. With
dependency injection.</p>
<pre lang="C++">
class Student
{
// Handle to EventLog writer to write to the logs
ILogWriter writer = null;
Public Student(ILogWriter writer)
{
this.writer = writer;
}
// This function will be called when the student has problem
public void Notify(string message)
{
writer.Write(message);
}
}
</pre>
<pre lang="C++">
class Main
{
Private void AddStudent
{
}
</pre>