SOLID Principles in Java
Omar Ismail
Senior Software Engineer @ Digitinary | Java & Spring Expert ? | AWS & Microservices Architect ? | FinTech & Open Banking Innovator ?? | Digital Payments Expert ?? | Top 200 IT Content Creator in Jordan ?? | 40K+ ??
Thanks TO : https://medium.com/nerd-for-tech/solid-principles-in-java-5cf926e44247
SOLID principles basically form the fundamental guidelines for building object-oriented, loosely coupled, robust, maintainable, and easily understandable applications. One of the most frequently asked interview questions, let's look at each one of them:
Single Responsibility: A class should have one and only one responsibility. We should write, change or maintain a class for only one purpose which gives us the advantage of cleaner, robust code and fewer test cases as to we know which functionality is covered in which class and which class would be modified in case of a change. For ex:
public class Vehicle{
public void printDetails() {}
public double calculate() {}
public void addtoDB() {}
}
The above class has three separate responsibilities: printing, calculation, and adding to the database. By applying SRP, we can separate the above class into three classes with separate responsibilities.
Open Closed?: A class should be open for extension but closed for modification which essentially means we do not want our existing code to be modified causing potential issues or bugs . Other developers incase of some functionality change should be able to extend our class and override some methods. For ex:
public class VehiclePrice {
public double Value(Vehicle v) {
if (v instanceof Car) {
return v.getValue() * 0.5;
if (v instanceof Truck) {
return v.getValue() * 0.8;
}
}
If we want to add one more type to this, say e-bike, we would have to modify the above class with one more if statement which goes against the principle. A better way is to let the subclasses override the Value method as per their type.
Liskov Substitution: Derived classes must be substitutable for the base class. In simple words, If class A is extending class B, we should be able to replace B with A, without disrupting the behavior of our program. As per OOPS concepts inheritance is a good practice but the Liskov principle mandates to use of inheritance with careful consideration. We should only use inheritance if our superclass is replaceable with a subclass in all the instances.
For ex: Classic Square Rectangle problem.
public class Rectangle {
private double height;
private double width;
public void setHeight(double h) { height = h; }
public void setWidht(double w) { width = w; }
//getters and calculateArea method
}
public class Square extends Rectangle {
public void setHeight(double h) {
super.setHeight(h);
super.setWidth(w);
}
public void setWidth(double h) {
领英推荐
super.setHeight(h);
super.setWidth(w);
}
}
As its clear base class Rectangle is clearly not replaceable by subclass Square, as the square has a constraint of equal height and width, so substituting Rectangle class with Square class breaks LSP.
Interface Segregation: No one should be required to implement methods in their classes that they will not use. Larger interfaces should be split into smaller ones. This ensures that implementing classes only need to be concerned about the methods that are useful to them. This gives us the flexibility to use only the required functionality. For ex:
public interface Vehicle {
public void drive();
public void stop();
public void openDoors();
}
public class Bike implements Vehicle {
// Can be implemented
public void drive() {...}
public void stop() {...}
// Can not be implemented
public void openDoors() {...}
}
For a bike class to implement the openDoors method does not make sense. This should be fixed by breaking the Vehicle interface into multiple smaller interfaces with likely functionality so that no class is forced to implement non-required methods.
Dependency Inversions?: A class should depend on abstraction(interfaces and abstract classes) and not on concretion (classes).
public class Car {
private Engine engine;
public Car(Engine e) {
engine = e;
}
public void start() {
engine.start();
}
}
public class Engine {
public void start() { //some implementation }
}
The above code will work for one engine but what if there are two types of engine, say diesel and petrol, it would mean modifying our class which is not a good idea.
This can be solved by adding an abstraction layer, so the car instead of directly depending on Engine now depends on EngineInterface. PetrolEngine or DieselEngine classes implement this interface and we can connect any of these to the Car class:
Hope this article gives a good idea of SOLID principles. Happy Learning :)
Android Lead at UBS
1 年https://medium.com/@myofficework000/solidifying-your-kotlin-code-applying-the-solid-principles-for-better-software-design-55a4121f9d73
Talked about the same topic Omar Ismail : PART 1 : https://www.dhirubhai.net/feed/update/urn:li:activity:6897834056172875776 PART 2 : https://www.dhirubhai.net/feed/update/urn:li:activity:6919308510467895296/ ??
PMP | Scrum Master | Project Manager | Web & Mobile Solution Technical Architecture | Lead Developer | DevOps Server Engineer | IT Consultant
2 年Thanks, Omar same as looking for design patterns
Camunda | Microservices | Java | Azure | Spring Boot | BPM | Ltimindtree | ex-TCSer
2 年??