The SOLID principles are a set of design principles in object-oriented programming aimed at creating more understandable, flexible, and maintainable software. The acronym SOLID stands for:
- S: Single Responsibility Principle (SRP)
- O: Open/Closed Principle (OCP)
- L: Liskov Substitution Principle (LSP)
- I: Interface Segregation Principle (ISP)
- D: Dependency Inversion Principle (DIP)
1. Single Responsibility Principle (SRP)
Definition: A class should have only one reason to change, meaning it should have only one job or responsibility.
// BAD Example
class Report {
public void generateReport() {
/*...*/
}
public void printReport() {
/*...*/
}
public void saveToFile() {
/*...*/
}
}
// GOOD Example
class ReportGenerator {
public void generateReport() {
/*...*/
}
}
class ReportPrinter {
public void printReport() {
/*...*/
}
}
class ReportSaver {
public void saveToFile() {
/*...*/
}
}
2. Open/Closed Principle (OCP)
Definition: Software entities (classes, modules, functions) should be open for extension but closed for modification.
// BAD Example
class Discount {
public double getDiscount(String customerType) {
if (customerType.equals("Premium")) {
return 0.2;
}
return 0.1;
}
}
// GOOD Example
interface DiscountStrategy {
double getDiscount();
}
class PremiumDiscount implements DiscountStrategy {
public double getDiscount() {
return 0.2;
}
}
class RegularDiscount implements DiscountStrategy {
public double getDiscount() {
return 0.1;
}
}
3. Liskov Substitution Principle (LSP)
Definition: Subtypes must be substitutable for their base types without altering the correctness of the program.
// BAD Example
class Bird {
public void fly() {}
}
class Ostrich extends Bird {
public void fly() {
throw new UnsupportedOperationException();
}
}
// GOOD Example
interface Bird {}
interface FlyingBird extends Bird {
void fly();
}
class Sparrow implements FlyingBird {
public void fly() {
/*...*/
}
}
class Ostrich implements Bird {}
4. Interface Segregation Principle (ISP)
Definition: Clients should not be forced to depend on interfaces they do not use.
// BAD Example
interface Worker {
void work();
void eat();
}
class Robot implements Worker {
public void work() {
/*...*/
}
public void eat() {
/*Does not apply*/
}
}
// GOOD Example
interface Workable {
void work();
}
interface Eatable {
void eat();
}
class Human implements Workable, Eatable {
public void work() {
/*...*/
}
public void eat() {
/*...*/
}
}
class Robot implements Workable {
public void work() {
/*...*/
}
}
5. Dependency Inversion Principle (DIP)
Definition: High-level modules should not depend on low-level modules. Both should depend on abstractions.
// BAD Example
class LightBulb {
public void turnOn() {}
public void turnOff() {}
}
class Switch {
private LightBulb bulb = new LightBulb();
public void operate() {
bulb.turnOn();
}
}
// GOOD Example
interface Switchable {
void turnOn();
void turnOff();
}
class LightBulb implements Switchable {
public void turnOn() {}
public void turnOff() {}
}
class Switch {
private Switchable device;
public Switch(Switchable device) {
this.device = device;
}
public void operate() {
device.turnOn();
}
}
Conclusion
Adopting the SOLID principles helps in building clean, maintainable, and scalable object-oriented systems. These principles are foundational to good software design and are essential for writing robust code.