Notes below extracted from: https://www.freecodecamp.org/news/introduction-to-solid-principles/ +------------------------------------------------------------------------------+ | S - Single-responsibility Principle +------------------------------------------------------------------------------+ Every class must have a single, focused responsibility, a single reason to change. CONSEQUENCE: Code is simpler, more classes, but each class is simple and focused public class Employee{ public String getDesignation(int employeeID){ // } public void updateSalary(int employeeID){ // } public void sendMail(){ // } } VS ---------------------------------------------------------------------------- public class Employee{ public String getDesignation(int employeeID){ // } public void updateSalary(int employeeID){ // } } public class NotificationService { public void sendMail() { // } } +------------------------------------------------------------------------------+ | O - Open-closed Principle +------------------------------------------------------------------------------+ components must be open for extension, but, closed for modification CONSEQUENCE: Extend code via subclassing, not modifying existing classes : creates code that is extendable outside of code base, : less likely to break existing code public class AreaCalculator(){ public double area(Shape shape){ double areaOfShape; if(shape instanceof Square){ // calculate the area of Square } else if(shape instanceof Circle){ // calculate the area of Circle } return areaOfShape; } VS ---------------------------------------------------------------------------- interface IAreaCalculator(){ double area(); } class Square implements IAreaCalculator{ @Override public double area(){ System.out.println("Calculating area for Square"); return 0.0; } } class Circle implements IAreaCalculator{ @Override public double area(){ System.out.println("Calculating area for Circle"); return 0.0; } } +------------------------------------------------------------------------------+ | L - Liskov Substitution Principle +------------------------------------------------------------------------------+ you must be able to replace a superclass object with a subclass object without affecting the correctness of the program CONSEQUENCE: When extending code, make sure you adhere to assumptions and : contracts of superclass, otherwise you may break code built for : superclasses assumptions abstract class Bird{ abstract void fly(); } class Eagle extends Bird { @Override public void fly() { // some implementation } } class Ostrich extends Bird { @Override public void fly() { // dummy implementation } } VS ---------------------------------------------------------------------------- abstract class FlyingBird{ abstract void fly(); } abstract class NonFlyingBird{ abstract void doSomething(); } class Eagle extends FlyingBird { @Override public void fly() { // some implementation } } class Ostrich extends NonFlyingBird { @Override public void doSomething() { // some implementation } } +------------------------------------------------------------------------------+ | I - Interface Segregation Principle +------------------------------------------------------------------------------+ you should build small, focused interfaces that do not force the client to implement behavior they do not need CONSEQUENCE: Code is simpler, in that dummy implementations do not need to : be spread throughout code base. If I is violated, to add more interfaces : all subclasses etc. must be reviewed and subsequently add the new interface : aspect interface IShapeAreaCalculator(){ double calculateArea(); double calculateVolume(); } class Square implements IShapeAreaCalculator{ double calculateArea(){ // calculate the area } double calculateVolume(){ // dummy implementation } } VS ---------------------------------------------------------------------------- interface IAreaCalculator { double calculateArea(); } interface IVolumeCalculator { double calculateVolume(); } class Square implements IAreaCalculator { @Override public double calculateArea() { // calculate the area } } class Cube implements IAreaCalculator, IVolumeCalculator { @Override public double calculateArea() { // calculate the area } @Override public double calculateVolume() {// calculate the volume } } +------------------------------------------------------------------------------+ | D - Dependency Inversion Principle +------------------------------------------------------------------------------+ high-level modules should not depend on low-level modules CONSEQUENCE: Violating D, leads to tight coupling between high level : classes and low level implementation. Leading to less flexible : more rigid code. Difficult to modify and extend. public interface Notification { void notify(); } public class EmailNotification implements Notification { public void notify() { System.out.println("Sending notification via email"); } } public class Employee { private EmailNotification emailNotification; public Employee(EmailNotification emailNotification) { this.emailNotification = emailNotification; } public void notifyUser() { emailNotification.notify(); } } VS ---------------------------------------------------------------------------- public interface Notification{ public void notify(); } public class Employee{ private Notification notification; public Employee(Notification notification){ this.notification = notification; } public void notifyUser(){ notification.notify(); } } public class EmailNotification implements Notification{ public void notify(){ //implement notification via email } } public static void main(String [] args){ Notification notification = new EmailNotification(); Employee employee = new Employee(notification); employee.notifyUser(); } Further Reading: https://www.digitalocean.com/community/conceptual-articles/s-o-l-i-d-the-first-five-principles-of-object-oriented-design https://www.baeldung.com/solid-principles https://www.globalnerdy.com/2009/07/15/the-solid-principles-explained-with-motivational-posters/