SOLID Principles

Prasad Bylapudi
3 min readAug 10, 2023

what are solid principles and why do we need to know them?

The SOLID principles are a set of five design principles in object-oriented programming that aim to create more maintainable, flexible, and scalable software. They were introduced by Robert C. Martin and serve as guidelines for writing clean and maintainable code. Let’s go through each of the SOLID principles with examples in JavaScript:

Single Responsibility Principle (SRP):

This principle states that a class should have only one reason to change, meaning it should have only one responsibility or job.

// Bad example
class UserSettings {
// This class has multiple responsibilities: saving, loading, and validating settings
saveSettings(settings) { /* ... */ }
loadSettings(userId) { /* ... */ }
validateSettings(settings) { /* ... */ }
}

// Good example
class UserSettings {
saveSettings(settings) { /* Implementation for saving settings */ }
loadSettings(userId) { /* Implementation for loading settings */ }
}

class SettingsValidator {
validateSettings(settings) { /* Implementation for validating settings */ }
}

Open/Closed Principle (OCP):

This principle suggests that a class should be open for extension but closed for modification. In other words, you should be able to add new functionality without changing existing code.

// Bad example
class Shape {
// This class handles drawing generic shapes
draw() { /* ... */ }
}

class Circle extends Shape {
// This class modifies the draw method for circles, violating OCP
draw() { /* ... */ }
}

// Good example
class Shape {
draw() { /* Implementation for drawing shapes */ }
}

class Circle extends Shape {
draw() { /* Implementation for drawing circles */ }
}

class Square extends Shape {
draw() { /* Implementation for drawing squares */ }
}

Liskov Substitution Principle (LSP):

This principle states that objects of a derived class should be able to replace objects of the base class without affecting the correctness of the program.

// Bad example
class Bird {
fly() { /* ... */ }
}

class Ostrich extends Bird {
// This class should not throw an error, violating LSP
fly() {
throw new Error("Ostriches can't fly!");
}
}

// Good example
class Bird {
fly() { /* Implementation for flying */ }
}

class Ostrich extends Bird {
fly() { /* Implementation for running (since ostriches can't fly) */ }
}

Interface Segregation Principle (ISP):

This principle suggests that clients should not be forced to depend on interfaces they do not use. In other words, it’s better to have multiple smaller interfaces rather than one large interface.

// Bad example
class Worker {
// This class has methods that are not relevant to all workers
work() { /* ... */ }
eat() { /* ... */ }
sleep() { /* ... */ }
}

// Good example
class Workable {
work() { /* Implementation for working */ }
}

class Eatable {
eat() { /* Implementation for eating */ }
}

class Sleepable {
sleep() { /* Implementation for sleeping */ }
}

Dependency Inversion Principle (DIP):

This principle states that high-level modules should not depend on low-level modules. Both should depend on abstractions. Additionally, abstractions should not depend on details; details should depend on abstractions.

// Bad example
class LightBulb {
turnOn() { /* ... */ }
turnOff() { /* ... */ }
}

class Switch {
constructor(bulb) {
this.bulb = bulb;
}
toggle() {
if (this.bulb.isOn()) { // This method call depends on the concrete LightBulb class
this.bulb.turnOff();
} else {
this.bulb.turnOn();
}
}
}

// Good example
class Switchable {
toggle() { /* Abstract method for toggling */ }
}

class LightBulb extends Switchable {
turnOn() { /* Implementation for turning on */ }
turnOff() { /* Implementation for turning off */ }
}

class Switch {
constructor(device) {
this.device = device;
}
toggle() {
this.device.toggle(); // This method call is now based on the abstract Switchable class
}
}

SOLID principles make our life easier as a developer.

Happy Learning!!!!!!!!

--

--