Learn OOP SOLID Principles Solid Way Using Java
SOLID is a collection of five object-oriented programming (OOP) design principles that strive to make the software more flexible, manageable, and scalable. Single Responsibility Principle, Open-Closed Principle, Liskov Substitution Principle, Interface Segregation Principle, and Dependency Inversion Principle are the acronyms for the SOLID principles.
Here’s an example of how to put the SOLID principles into action in Java:
Single Responsibility Principle (SRE)
Principle of Single Responsibility (SRP)
According to the SRP, a class should have just one reason to modify. To put it another way, a class should only have one responsibility. This idea contributes to code that is more focused and easier to maintain.
public class Order {
private List<Item> items;
public double calculateTotal() {
// calculate the total price of all items in the order
}
public void addItem(Item item) {
// add an item to the order
}
public void removeItem(Item item) {
// remove an item from the order
}
}
public class Item {
private String name;
private double price;
// getters and setters
}
Open/Closed Principle
The Principle of Open-Closed (OCP)
According to the OCP, a class should be accessible to extension but closed to modification. Put another way, you should be able to add new functionality to a class without altering its existing code.
public interface Shape {
double getArea();
}
public class Rectangle implements Shape {
private double width;
private double height;
// constructor, getters, and setters
@Override
public double getArea() {
return width * height;
}
}
public class Circle implements Shape {
private double radius;
// constructor, getters, and setters
@Override
public double getArea() {
return Math.PI * radius * radius;
}
}
Liskov Substitution
Substitution Principle of Liskov (LSP)
According to the LSP, subtypes should be interchangeable with their base types. In other words, you should be able to use a subclass object in place of a superclass object without affecting the correctness of the program.
public class Animal {
public void eat() {
// eat some food
}
}
public class Dog extends Animal {
public void bark() {
// bark loudly
}
}
public class Cat extends Animal {
public void meow() {
// meow softly
}
}
Interface Segregation
The Interface Segregation Principle (ISP)
According to the ISP, clients should not be compelled to rely on interfaces they do not use. In other words, you should divide a huge interface into smaller, more specialised ones.
public interface Movable {
void move();
}
public interface Drawable {
void draw();
}
public class Car implements Movable {
@Override
public void move() {
// move the car
}
}
public class Circle implements Movable, Drawable {
@Override
public void move() {
// move the circle
}
@Override
public void draw() {
// draw the circle
}
}
Dependency Injection
Principle of Dependency Inversion (DIP)
According to the DIP, high-level modules should not rely on low-level modules. Both should instead rely on abstractions. Abstractions should not be based on specifics. Abstractions should drive details.
public interface DataService {
void saveData(String data);
}
public class DatabaseService implements DataService {
@Override
public void saveData(String data) {
// save the data to a database
}
}
public class FileService implements DataService {
@Override
public void saveData(String data) {
// save the data to a file
}
}
public class DataManager{
public DataManager(DataService dataService) {
this.dataService = dataService;
}
public void save(String data) {
dataService.saveData(data);
}
}
The DataService interface, an abstraction, is what the DataManager class in the example above depends on. The DataService interface-dependent DatabaseService and FileService classes will handle the implementation specifics. The DataManager class is unaffected by this design, making it simple to switch between various data storage solutions.
If you like what you read Buy me a cup of coffee.
If you enjoyed reading this, don’t forget the applause. 👏
Thank you.