SOLID Principles
These principles are used to make software design more understandable, flexible, and maintainable.
- Single Responsibility Principle (SRP)
- Open Closed Principle (OCP)
- Liskov Substitution Principle (LSP)
- Interface Segregation Principle (ISP)
- Dependency Inversion Principle (DIP)
1. Single Responsibility Principle (SRP)
Definition: A class should have only one reason to change.
Implementation
The code below violates the SRP principle as it mixes open-gate and close-gate responsibilities with the main function of servicing the vehicle.
public class GarageStation
{
public void DoOpenGate()
{
// Open the gate functionality
}
public void PerformService(Vehicle vehicle)
{
// Check if garage is opened
// Finish the vehicle service
}
public void DoCloseGate()
{
// Close the gate functionality
}
}
//Correct Version
public interface IGarageUtility
{
void OpenGate();
void CloseGate();
}
public class GarageStationUtility : IGarageUtility
{
public void OpenGate()
{
// Open the Garage for service
}
public void CloseGate()
{
// Close the Garage functionality
}
}
public class GarageStation
{
private IGarageUtility _garageUtil;
public GarageStation(IGarageUtility garageUtil)
{
this._garageUtil = garageUtil;
}
public void OpenForService()
{
_garageUtil.OpenGate();
}
public void DoService()
{
// Check if service station is opened and then
// Finish the vehicle service
}
public void CloseGarage()
{
_garageUtil.CloseGate();
}
}
2. Open Closed Principle (OCP)
Definition: Software entities (classes, modules, functions, etc.) should be open for extension but closed for modification.
Implementation
The code below violates the OCP principle if the bank introduces a new Account type.
public class Account
{
public decimal Interest { get; set; }
public decimal Balance { get; set; }
// Members and function declaration
public decimal CalcInterest(string accType)
{
if (accType == "Regular") // savings
{
Interest = (Balance * 4) / 100;
if (Balance < 1000) Interest -= (Balance * 2) / 100;
if (Balance < 50000) Interest += (Balance * 4) / 100;
}
else if (accType == "Salary") // salary savings
{
Interest = (Balance * 5) / 100;
}
else if (accType == "Corporate") // Corporate
{
Interest = (Balance * 3) / 100;
}
return Interest;
}
}
We can apply OCP by using interface, abstract class, abstract methods, and virtual methods when we want to extend functionality. Here, we have used the interface for example only, but you can go as per your requirement.
interface IAccount
{
// members and function declaration, properties
decimal Balance { get; set; }
decimal CalcInterest();
}
// Regular savings account
public class RegularSavingAccount : IAccount
{
public decimal Balance { get; set; } = 0;
public decimal CalcInterest()
{
decimal Interest = (Balance * 4) / 100;
if (Balance < 1000) Interest -= (Balance * 2) / 100;
if (Balance < 50000) Interest += (Balance * 4) / 100;
return Interest;
}
}
// Salary savings account
public class SalarySavingAccount : IAccount
{
public decimal Balance { get; set; } = 0;
public decimal CalcInterest()
{
decimal Interest = (Balance * 5) / 100;
return Interest;
}
}
// Corporate Account
public class CorporateAccount : IAccount
{
public decimal Balance { get; set; } = 0;
public decimal CalcInterest()
{
decimal Interest = (Balance * 3) / 100;
return Interest;
}
}

Join the conversation! Your thoughts help the community grow.