3 minutes
6: OOP Design Principles in Java
OOP Design Principles and Patterns in Java – Wrapping Up the Series
Introduction
After exploring Java’s core OOP concepts, classes & objects, inheritance, polymorphism, and abstraction, it’s time to tie everything together. In this final chapter, we’ll look at the guiding principles and common design patterns that help you write maintainable, flexible, and scalable object-oriented code in Java. These patterns aren’t magic, but building blocks and best practices you’ll revisit in real-world projects.
1. Composition Over Inheritance
- Inheritance creates an “is-a” relationship, but can lead to tight coupling and fragile hierarchies.
- Composition builds a “has-a” relationship, letting you assemble behavior at runtime.
Example:
public class Engine { void start() { /*...*/ } }
public class Car {
private final Engine engine;
public Car(Engine engine) {
this.engine = engine;
}
public void start() {
engine.start();
}
}
Here, Car
uses Engine
without subclassing it, easier to swap, test, and evolve.
2. SOLID Principles
- S – Single Responsibility Principle (SRP): A class should have only one reason to change.
- O – Open/Closed Principle (OCP): Classes 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): Favor many small, specific interfaces over one large, general-purpose interface.
- D – Dependency Inversion Principle (DIP): Depend on abstractions (interfaces or abstract classes), not concrete implementations.
Teaching Tip:
Use real code examples to show a class violating SRP by handling logging, persistence, and business logic all at once, then refactor it into focused classes.
3. Common Design Patterns
a. Factory Method
Encapsulates object creation:
public interface AnimalFactory { Animal create(); }
public class DogFactory implements AnimalFactory {
public Dog create() { return new Dog(); }
}
Let clients use AnimalFactory
without knowing concrete types.
b. Strategy
Defines a family of algorithms:
public interface PaymentStrategy { void pay(int amount); }
public class CreditCardStrategy implements PaymentStrategy { /*...*/ }
public class PayPalStrategy implements PaymentStrategy { /*...*/ }
At runtime, choose which PaymentStrategy
to use.
c. Observer
Keeps objects in sync:
public interface Observer { void update(); }
public class Subject {
private List<Observer> observers;
void attach(Observer o) { observers.add(o); }
void notifyAll() { for (Observer o : observers) o.update(); }
}
Good for event-driven designs.
d. Decorator
Adds responsibilities dynamically:
public interface Coffee { double cost(); }
public class SimpleCoffee implements Coffee { public double cost() { return 2; } }
public class MilkDecorator extends CoffeeDecorator {
public double cost() { return super.cost() + 0.5; }
}
Layer decorators to combine behaviors.
4. Anti-Patterns to Avoid
- God Object: A class that knows too much or does too much, break into smaller pieces.
- Spaghetti Inheritance: Deep and tangled hierarchies, prefer composition or interfaces.
- Circular Dependencies: Classes depending on each other, introduce an abstraction or mediator.
5. Refactoring Towards Better OOP
- Identify duplicate code, extract common behaviors into superclasses or helper classes.
- Spot large classes violating SRP, split responsibilities.
- Replace conditional logic on types (
instanceof
) with polymorphic calls.
6. Final Thoughts
OOP in Java is more than syntax, it’s about modeling your domain in terms of objects, relationships, and behaviors. By following principles like SOLID and applying patterns judiciously, your code becomes easier to test, evolve, and maintain.
Series Wrap-Up:
- Classes & Objects: Foundation of state and behavior.
- Inheritance: Code reuse and hierarchy, with careful use.
- Polymorphism: Write flexible APIs against abstractions.
- Abstraction: Abstract classes vs. interfaces for design clarity.
- Design Principles: SOLID to guide maintainability.
- Design Patterns: Proven solutions for common problems.
Thanks for following this OOP series! Keep practicing, revisit these patterns, and adapt them to your projects. Happy coding!
End of series.