Skip to main content

Object-Oriented Design Principles in Java

Introduction​

Object-oriented design principles are guidelines that help you design robust, maintainable, and scalable software. These principles promote best practices for writing clean and efficient object-oriented code. Understanding and applying these principles is crucial for developing high-quality software.

SOLID Principles​

The SOLID principles are five key design principles that guide object-oriented design and programming. These principles were introduced by Robert C. Martin (Uncle Bob) and are widely recognized in the software development community.

Single Responsibility Principle (SRP)​

A class should have only one reason to change, meaning that a class should have only one job or responsibility.

Example​

public class Book {
private String title;
private String author;

// Methods related to Book properties
public String getTitle() { return title; }
public void setTitle(String title) { this.title = title; }
public String getAuthor() { return author; }
public void setAuthor(String author) { this.author = author; }
}

public class BookPrinter {
// Method to print book details
public void printBook(Book book) {
System.out.println("Title: " + book.getTitle());
System.out.println("Author: " + book.getAuthor());
}
}

Open/Closed Principle (OCP)​

Software entities (classes, modules, functions, etc.) should be open for extension but closed for modification. This means you should be able to add new functionality without changing existing code.

Example​

public abstract class Shape {
public abstract double area();
}

public class Circle extends Shape {
private double radius;

public Circle(double radius) {
this.radius = radius;
}

@Override
public double area() {
return Math.PI * radius * radius;
}
}

public class Rectangle extends Shape {
private double width;
private double height;

public Rectangle(double width, double height) {
this.width = width;
this.height = height;
}

@Override
public double area() {
return width * height;
}
}

Liskov Substitution Principle (LSP)​

Objects of a superclass should be replaceable with objects of a subclass without affecting the correctness of the program. This means that a subclass should enhance, not weaken, the functionality of the superclass.

Example​

public class Bird {
public void fly() {
System.out.println("Flying");
}
}

public class Sparrow extends Bird {
// Sparrow can fly, no problem here
}

public class Ostrich extends Bird {
// Ostrich cannot fly, violating LSP
@Override
public void fly() {
throw new UnsupportedOperationException("Ostrich cannot fly");
}
}

Interface Segregation Principle (ISP)​

Clients should not be forced to depend on interfaces they do not use. This means that creating specific interfaces for each type of client improves code flexibility and maintenance.

Example​

public interface Worker {
void work();
}

public interface Eater {
void eat();
}

public class Human implements Worker, Eater {
@Override
public void work() {
System.out.println("Human working");
}

@Override
public void eat() {
System.out.println("Human eating");
}
}

public class Robot implements Worker {
@Override
public void work() {
System.out.println("Robot working");
}
}

Dependency Inversion Principle (DIP)​

High-level modules should not depend on low-level modules. Both should depend on abstractions. Abstractions should not depend on details. Details should depend on abstractions.

Example​

public interface Keyboard {
void type();
}

public class MechanicalKeyboard implements Keyboard {
@Override
public void type() {
System.out.println("Typing with mechanical keyboard");
}
}

public class Computer {
private Keyboard keyboard;

public Computer(Keyboard keyboard) {
this.keyboard = keyboard;
}

public void type() {
keyboard.type();
}
}

Additional Design Principles​

DRY (Don't Repeat Yourself)​

Avoid duplication of code by abstracting common functionality into methods or classes. This reduces redundancy and improves maintainability.

KISS (Keep It Simple, Stupid)​

Write simple and straightforward code that is easy to understand. Avoid overcomplicating solutions, as simpler code is easier to maintain and debug.

YAGNI (You Aren't Gonna Need It)​

Do not add functionality until it is necessary. This principle helps in avoiding over-engineering and keeping the codebase manageable.

Conclusion​

Object-oriented design principles are essential for writing clean, maintainable, and scalable code. By adhering to SOLID principles and other best practices like DRY, KISS, and YAGNI, you can develop robust and efficient software applications. Understanding and applying these principles will significantly improve your skills as a Java developer.