You are on page 1of 26

SOLID PRINCIPLES

• Solid Principles are the design principles that enable us manage most
of the software design problems

• SOLID Acronym

S:Single Responsibility Principle(SRP)


O:Open closed Principle(OSP)
L:Liskov substitution Principle(LSP)
I:Interface Segregation principle(ISP)
D:Dependency Inversion Principle(DIP)
SINGLE RESPONSIBILITY PRINCIPLE

“A class should have only one reason to change”

This means that every module or class should have responsibility over a
single part of the functionality provided by the software and that
responsibility should be entirely encapsulated by the class

It provides Maintainability,Testibility,Flexibility and


Extensibility,Parallel Development and Loose Coupling
• Each class and module should focus on a single task at a a time

• Everything in the class should be related to that single purpose.

• With SRP,Classes become smaller and cleaner

• Code is less fragile

• There can be many members in the class as long as they related to the
single responsibility
Problem:

interface Iuser
{
bool Login(string username,string password);
bool Register(string username,string password,string email);
bool LogError(string error);
bool SendEmail(string emailContent);
}

In this interface we can see that the methods LogError and SendEmail doesn’t
have same functionality that a user is provided with so they should have a
separate interface A user is only related with the Login and Register method
the functionality of LogError And SendEmail is not directly related to the user
So according to the single responsibility principle

Solution:

interface Iuser
{
bool Login(string username,string password);
bool Register(string username,string password,string email);
}

interface Ilogger
{
bool LogError(string error);
}

interface Iemail
{
bool SendEmail(string emailContent);
}
OPEN CLOSED PRINCIPLE

“Software entities such as classes,modules,functions,etc should be open


for extension, but closed for modification”

It means any new functionality should be implemented by adding new


classes, attributes and methods, instead of changing the current ones or
existing ones.

The simplest way to apply OCP is to implement the new


functionality on new derived classes Allow clients to access the
original class with abstract interface
Why OCP?

If Not followed

• End up testing the entire functionality

• QA Team need to test the entire flow

• Costly Process for the Organization

• Breaks the Single responsibility as well

• Maintenance overheads increase on the classes.


Problem:

Public class Employee


{
public int id { //getters //setters}
public string Name { //getters //setters}
public string EmployeeType { //getters //setters}

public Employee(){
}

public Employee(int id,string name,string employeeType)


{
this.ID=id;this.name=name,this.EmployeeType=employeeType;
}
public decimal CalculateBonus(decimal salary)
{
if(this.EmployeeType == “Permanent”)
return salary * .1M;
else
return salary * .05M;
}

public override string ToString()


{
return string.Format(“ID : {0} Name{1}”,this.ID,this.Name);
}
}

In the above example if we want to add a new method(CalculateBonus) for we


have to make changes in the code it’s always better to make a method abstract
or develop an interface of the method
Solution:

Public abstract class Employee


{

public int id { //getters //setters}


public string Name { //getters //setters}
public string EmployeeType { //getters //setters}
public Employee(){
}
public Employee(int id,string name,string employeeType){
this.ID=id;this.name=name,this.EmployeeType=employeeType;
}
public abstract decimal CalculateBonus(decimal salary);
public override string ToString()
{
return string.Format(“ID : {0} Name : {1}”,this.ID,this.Name);
}
}
Public class Permanent Employee :Employee
{
public PermanentEmployee()
{ }

public PermanentEmployee(int id, string name) : base(id,name)


{ }

public override decimal CalculateBonus(decimal salary)


{
return (salary *.1M);
}
}
Public class Temperory Employee :Employee
{
public TemperoryEmployee()
{ }

public TemperoryEmployee(int id, string name) : base(id,name)


{ }

public override decimal CalculateBonus(decimal salary)


{
return (salary *.05M);
}
}
LISKOV SUBSTITUTION PRINCIPLE

“S is a subtype of T,then objects of type T may be replaced with objects of type S”

• LSP is a particular definition of a subtyping relation called(strong)


behavioural subtyping

• NO new exceptions can be thrown by the subtype

• Clients should know which specific subtype they are calling

• New derived classes just extend without replacing the functionality of old
classes
In the previous example that we used in OCP ,now we want add a new
employee category that is contractEmployee the contract employee will not get
the bonus and we want to display the minimum salary of
three(Temperory,Permanent and contract employee) now we will make
interfaces for get the Minimum salary and for Calculating the bonus .Contract
Employee will not implement the Calculate bonus interface

Interface IEmployeeBonus
{
decimal CalculateBonus(decimal salary);
}

Interface IEmployee
{
int ID{ get; set;}
string Name { get; set; }
decimal GetMinimumSalary();
}
Public class PermanentEmployee: IEmployeeBonus, IEmployee
{
public PermanentEmployee()
{ }

public PermanentEmployee(int id, string name) : base(id,name)


{ }

public override decimal CalculateBonus(decimal salary)


{
return (salary *.1M);
}
public override decimal GetMinimumSalary()
{
return 15000;
}
}

Similary we can do for Temperory Employee Class


Public class ContractEmployee: IEmployee
{
public ContractEmployee()
{ }

public ContractEmployee(int id, string name) : base(id,name)


{ }

public override decimal GetMinimumSalary()


{
return 10000;
}
}
INTERFACE SEGREGATION PRINCIPLE

“No client should be forced to depend on methods it does not use”

One fat Interface need to be split to many smaller and relevant


interfaces so that clients can know about the interfaces that are relevant
to them
We can take an example of printer:
Problem:

public interface IPrintTasks


{
bool PrintContent(string content);
bool ScanContent(string content);
bool FaxContent(string content);
bool PhotoCopyContent(string content);
bool PrintDuplexContent(string content);
}

Since all the printers cannot perform all these tasks .So we will apply
interface segregation Principle for common printers and then separate
interfaces for expensive and most expensive printers so according printers
can choose interfaces relevant to it.
Solution:

public interface IPrintTasks


{
bool PrintContent(string content);
bool ScanContent(string content);
bool PhotoCopyContent(string content);
}

public interface IFaxContent


{
bool FaxContent(string content);
}

public interface IDuplexContent


{
bool PrintDuplexContent(string content);
}
DEPENDENCY INVERSION PRINCIPLE(DIP)

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

This means that the interaction between high level and low level modules
should be thought of as an abstract interaction between them
Problem:

Presentation Business DataAccess


Layer Layer Layer

public classBusinessLogicLayer
{
private readonly DataAccessLayer DAL;
public BusinessLogicLayer()
{
DAL = new DataAccessLayer();
}
public void Save(Object details){ //perform save}
}

public class DataAccessLayer


{
public void Save(Object details){ //perform save}
}
Presentation
Layer

Data Access
Layer
References

Repository
Interface inherits
public classBusinessLogicLayer
{
private readonly IRepository Layer DAL;
public BusinessLogicLayer(IRepositoryLayer repositoryLayer )
{
DAL = new DataAccessLayer();
}
public void Save(Object details){ //perform save}
}

Public interface IRepositoryLayer


{
void save(Object details);
}

public class DataAccessLayer : IRepositoryLayer


{
public void Save(Object details){ //perform save}
}
Why Solid?

If we don't follow SOLID Principles we

• End up with tight or strong coupling of the code with many other
modules/applications

• Tight coupling causes time to implement any new requirement, features


or any bug fixes and some times it creates unknown issues

• End up with a code which is not testable

• End up with duplication of code

• End up creating new bugs by fixing another bug

• End up with many unknown issues in the application development cycle


Following SOLID Principles helps us to

• Achieve reduction in complexity of code

• Increase maintenance,readability and extensibility

• Reduce error and implement

• Reusability

• Achieve Better testability

• Reduce tight coupling

You might also like