In recent Java versions, the conversation around composition versus inheritance has evolved significantly, with a stronger emphasis on composition as a more flexible and maintainable approach. While inheritance has traditionally been a cornerstone of object-oriented programming, composition allows for greater modularity, reducing the tight coupling associated with class hierarchies. This shift is partly due to the introduction of features like interfaces with default methods in Java 8, which enable more dynamic and flexible design patterns.
// Using Inheritance
class Animal {
public void sound() {
System.out.println("Animal sound");
}
}
class Dog extends Animal {
@Override
public void sound() {
System.out.println("Bark");
}
}
// Using Composition
class BarkBehavior {
public void makeSound() {
System.out.println("Bark");
}
}
class Dog {
private BarkBehavior barkBehavior;
public Dog(BarkBehavior barkBehavior) {
this.barkBehavior = barkBehavior;
}
public void performSound() {
barkBehavior.makeSound();
}
}
// Usage
Dog dog = new Dog(new BarkBehavior());
dog.performSound(); // Outputs: Bark
How do I avoid rehashing overhead with std::set in multithreaded code?
How do I find elements with custom comparators with std::set for embedded targets?
How do I erase elements while iterating with std::set for embedded targets?
How do I provide stable iteration order with std::unordered_map for large datasets?
How do I reserve capacity ahead of time with std::unordered_map for large datasets?
How do I erase elements while iterating with std::unordered_map in multithreaded code?
How do I provide stable iteration order with std::map for embedded targets?
How do I provide stable iteration order with std::map in multithreaded code?
How do I avoid rehashing overhead with std::map in performance-sensitive code?
How do I merge two containers efficiently with std::map for embedded targets?