Explore the core differences between composition and inheritance in object-oriented programming with scenario-based questions designed to reinforce understanding of class relationships, code reuse, and design patterns. This quiz helps you assess when to prefer composition over inheritance and recognize their respective strengths and limitations.
When designing a system where behavior can be added to an object at runtime, which principle is typically more appropriate—composition or inheritance?
Explanation: Composition is generally more suitable when you want to add or change behaviors at runtime because it allows objects to be assembled with different capabilities dynamically. Inheritance, while useful for sharing code, is static and determined at compile time. Association and aggregation describe relationships but do not themselves address dynamic behavior modification. Choosing composition leads to more flexible and modular designs in such scenarios.
Suppose you have two unrelated classes, Car and Boat, both needing a feature to play music. Which object-oriented approach should you use to avoid code duplication?
Explanation: Composition lets you create a separate MusicPlayer component and inject it into both Car and Boat, allowing shared functionality without forcing them into an artificial inheritance hierarchy. Inheritance would require Car and Boat to share a common ancestor, which is not logical since they are unrelated. Overloading deals with method signatures, not code sharing, and encapsulation is about restricting access rather than reuse between classes.
According to the Liskov Substitution Principle, which problem can occur if inheritance is used inappropriately between classes that do not share true 'is-a' relationships?
Explanation: Incorrect program behavior can occur when a subclass does not properly extend the behavior of its superclass, violating the 'is-a' relationship demanded by the Liskov Substitution Principle. This can lead to unexpected results when code written for the parent class is supplied with a subclass. Improved modularity, optimized performance, and enhanced security are not the typical outcomes of misapplied inheritance and are therefore incorrect choices.
Which design pattern exemplifies the use of composition to delegate responsibilities to helper objects rather than relying on class inheritance?
Explanation: The Strategy pattern exemplifies composition by allowing an object to delegate certain behaviors to helper objects or strategies, offering great flexibility in changing behavior at runtime. The Singleton pattern concerns instance control and is unrelated to composition. Template Method is based on inheritance and fixed steps, while Decorator uses both inheritance and composition, but its main goal is to extend functionality, not necessarily delegate responsibility as in Strategy.
When should inheritance be avoided to prevent fragile or overly deep class hierarchies in a codebase?
Explanation: Inheritance should be avoided if classes have behaviors that can change independently, as this leads to complex and fragile hierarchies that are hard to maintain. In such cases, using composition enables more flexible design. Subclasses should be polymorphic and used for real 'is-a' relationships, making inheritance correct in those contexts. Tightly coupling classes is generally undesirable, and inheritance is not recommended for that purpose.