SOLID Principles
while design a system we should follow SOLID principle, so that the code will be more flexible, robust & easy to enhance for future.
The solid principle is combination of below 5 principles
1. Single Responsibility Principle
2. Open / Closed Principle
3. Liskov Substitution Principle (LSP)
4. Interface Segregation Principle (ISP)
5. Dependency Inversion Principle (DIP)
1. Single Responsibility Principles :
Design the classes so that each class should have single purpose. This does not mean that each class should have only one method but that all of the members in the class are related to the class's primary functions. If a class has multiple responsibility that should be separated into new classes.Example: in one project if we need to read data from any service provider parse that data & take any action on that data.
class RequestAlert
{
public:
void RequestData()
{
cout<<"Read data from a server"<<endl;
}
void PerseData()
{
cout<<"Parse that data"<<endl;
}
void TakeAlert()
{
cout<<"Alert to the users"<<endl;
}
};
Here we perform 3 different tasks in one single class. So it breaks the single responsibility principle.
so we have to create 3 different classes for this(Request class, Parse class & Alert class).
2. Open/Closed Principle :
Then open/close principle, states that the design should be closed for modification and open for extension. The "closed" part of the state that once a module has been developed and tested, the code should only be adjusted to correct bugs. The "open" part says that you should be able to extend existing code in order to introduce new functionality.Example:
In a game design we can have 3 types of troops dragon, giant, archers; all the 3 types of troops have different properties, behavior and attack target. If we use each functionality individually then it will be difficult if we want to add a new troop type. So we can use following design so that it will easy to extend in future.
3. Liskov Substitution Principle (LSP) :
The Liskov Substitution Principle says that the object of a derived class should be able to replace an object of he base class without bringing any errors in the the system or modifying the behavior of the base class.If S is sub set of T, an object of T could be replaces by object of S without impacting the program and bringing any error in the system. Let's say yu have a class Rectangle and another class Square. Square is as Rectangle, or in other words, it inherits the Rectangle class. So as the Liskov Substitution Principle states, we should able to replace object of Rectangle by the object of Square without brining any undesirable change or error in the system.
class Rectangle
{
int width;
int height;
public:
Rectangle(int h, int w)
{
width = w;
height = h;
}
void setWidth(int w)
{
width = w;
}
void setHeight(int h)
{
height = h;
}
void calculateArea()
{
cout<<"Area is "<<height*width<<endl;
}
};
class Square : public Rectangle
{
public:
Suare(int val) : Rectangle(val, val)
{
}
};
int main()
{
Rectangle *s = new Square(10);
s->calculateArea();
return 0;
}
If user modify width using setWidth() function then the result will be wrong as in Square both width & height will be same. This will be problem even if Sqaure class is subset of Rectangle class. So this breaks LSP.
Solution of the problem is :
class Shape
{
public:
virtual void calculateArea()=0;
};
class Rectangle : public Shape
{
int width;
int height;
public:
Rectangle(int h, int w)
{
width = w;
height = h;
}
void setWidth(int w)
{
width = w;
}
void setHeight(int h)
{
height = h;
}
void calculateArea()
{
cout<<"Area is "<<height*width<<endl;
}
};
class Square : public Shape
{
int side;
public:
Square(int val)
{
side = val;
}
void setSide(int val)
{
side = val;
}
void calculateArea()
{
cout<<"Area is "<<side*side<<endl;
}
};
4. Interface Segregation Principle (ISP) :
The Interface Segregation Principle (ISP) specifies that clients should not be forced to depend upon interfaces that they do not use. This rule means that when one class depends upon another, the number of members in the interface that is visible to the dependent class should be minimized.Example: currently we have cash payment system so the current structure is is below
class payment{
string name;
string address;
int phonenumber;
int price;
};
if we want to change upgrade the system to card-payment system then we have to save card information in current struct, so the current struct will be
class payment{
string name;
string address;
int phonenumber;
int price;
string cardnumber;
string cardname;
cardtype type;
string bankname;
};
it will work but in cash payment unnecessary card infromation is required to store. so it will break Interface Segregation principle.
so we have to divide this into 2 interfaes IPayment & Icardpayment
class IPayment{
string name;
string address;
int phonenumber;
int price;
};
class ICardPayment
{
string cardnumber;
string cardname;
cardtype type;
string bankname;
};
In cash payment class we have to inherit IPayment interface.
In online card payment & CardPayment we have to use both interface IPayment & ICardPayment.
5. Dependency Inversion Principle (DIP) :
The Dependency Inversion Principle (DIP) is compose of two statements.1. High level modules should not depend upon low level modules. Both should depend upon abstractions.
2. Abstractions should not depend upon details. Details should depends upon abstraction.
Example: In one system we have to write the result in monitor or to a file. In that case we can write in 'if-else' block. So our class look like
enum mode
{
CONSOLE,
FILE
};
class ResultDisplay {
void sendresult(mode m)
{
if(m == CONSOLE)
cout<<"Hello how are you";
else if(m == FILE)
{
ofstream myfile;
myfile.open ("example.txt");
myfile << "Writing this to a file.\n";
myfile.close();
}
}
};
if we want to send result to a email, then we have to add a new type in enum mode & add another if-else for mail, which fails open/close principle. So we have to design that in following
class WriteResult
{
virtual void result()==0;
}
class Consol: public WriteResult
{
void result()
{
cout<<"Hello how are you";
}
};
class writefile: public WriteResult
{
void result()
{
ofstream myfile;
myfile.open ("example.txt");
myfile << "Writing this to a file.\n";
myfile.close();
}
};
class Result
{
WriteResult *res;
Result(WriteResult* p)
{
res = p;
}
void sendResult()
{
res.result();
}
}

Comments
Post a Comment