The SOLID principles are a set of five object-oriented design principles that help developers create more maintainable, understandable, and flexible software systems. They are often applied during software development using object-oriented programming languages like Java.
| Acronym | Principle | Description |
|---|---|---|
| S | Single Responsibility Principle (SRP) | A class should have only one reason to change. |
| O | Open/Closed Principle (OCP) | A class should be open for extension but closed for modification. |
| L | Liskov Substitution Principle (LSP) | Subtypes must be substitutable for their base types. |
| I | Interface Segregation Principle (ISP) | No client should be forced to depend on methods it does not use. |
| D | Dependency Inversion Principle (DIP) | High-level modules should not depend on low-level modules. Both should depend on abstractions. |
Java Case Study Example: Online Notification System
We will design a notification system that supports Email and SMS notifications. Later, we’ll apply each SOLID principle to improve the system.
❌ Initial (Non-SOLID) Design:
java
public class NotificationService {
public void sendNotification(String type, String message) {
if (type.equals("EMAIL")) {
System.out.println("Sending Email: " + message);
} else if (type.equals("SMS")) {
System.out.println("Sending SMS: " + message);
}
}
}
✅ Applying SOLID Principles:
- Single Responsibility Principle (SRP) Problem: NotificationService handles both logic and message formatting.
Fix: Split responsibilities into separate classes.
public class EmailSender {
public void send(String message) {
System.out.println("Sending Email: " + message);
}
}
public class SmsSender {
public void send(String message) {
System.out.println("Sending SMS: " + message);
}
}
Now, each class has one reason to change: either Email or SMS functionality.
2. Open/Closed Principle (OCP)
Problem: To add a new notification type (e.g., Push), we must modify NotificationService.
Fix: Use abstraction and polymorphism to allow extensions.
public interface Notification {
void send(String message);
}
public class EmailNotification implements Notification {
public void send(String message) {
System.out.println("Sending Email: " + message);
}
}
public class SmsNotification implements Notification {
public void send(String message) {
System.out.println("Sending SMS: " + message);
}
}
public class NotificationService {
private Notification notification;
public NotificationService(Notification notification) {
this.notification = notification;
}
public void send(String message) {
notification.send(message);
}
}
Now we can add PushNotification without modifying existing code.
3. Liskov Substitution Principle (LSP)
Problem: If a subclass overrides a method in a way that breaks functionality, LSP is violated.
Fix: Ensure all subclasses can be used interchangeably.
public class PushNotification implements Notification {
public void send(String message) {
System.out.println("Sending Push Notification: " + message);
}
}
// Works with existing NotificationService
Notification notification = new PushNotification();
notification.send("LSP test");
PushNotification behaves like other Notification implementations — no behavior breaks.
4. Interface Segregation Principle (ISP)
Problem: A fat interface might force classes to implement unused methods.
Fix: Split interfaces based on specific roles.
public interface EmailSender {
void sendEmail(String message);
}
public interface SmsSender {
void sendSms(String message);
}
// Implement only what you need
public class EmailService implements EmailSender {
public void sendEmail(String message) {
System.out.println("Sending Email: " + message);
}
}
5. Dependency Inversion Principle (DIP)
Problem: High-level modules depend on low-level modules.
Fix: Depend on abstractions (interfaces), not concrete classes.
public class NotificationManager {
private final Notification notification;
public NotificationManager(Notification notification) {
this.notification = notification;
}
public void notifyUser(String message) {
notification.send(message);
}
}
Now NotificationManager depends on the abstraction Notification, not on EmailNotification or SmsNotification.
✅ Final Summary
| Principle | Applied Example |
|---|---|
| SRP | Split Email/SMS into separate classes |
| OCP | New types added without modifying base code |
| LSP | All notifications behave similarly |
| ISP | Interfaces are small and focused |
| DIP |
NotificationManager depends on Notification interface |
Top comments (0)