Bird
Raised Fist0

When to Use Inheritance vs Composition - The Rule Every Senior Engineer Knows

LLDmediumInterview freq: high
Choose your preparation mode4 modes available
▶
Class Trace
Step 1/4
BaseComponent abstract class

BaseComponent is an abstract class holding shared state 'id' and volatile 'active' flag with synchronized methods to modify it.

🎯 Tests whether candidate understands abstract class is used over interface because it holds instance state and uses volatile for thread visibility and synchronized for atomic state changes.
public abstract class BaseComponent {
    protected String id;
    protected volatile boolean active;
    public synchronized void activate() {
        active = true;
    }
    public synchronized void deactivate() {
        active = false;
    }
}
BehaviorContract interface and ConcreteComponent realization

BehaviorContract is an interface defining behavior with no state, implemented by ConcreteComponent which composes a BehaviorContract instance.

🎯 Tests if candidate knows interface is used here to enforce OCP (Open-Closed Principle) for behavior extension without modifying ConcreteComponent, and that interface cannot hold state in Java.
public interface BehaviorContract {
    void execute();
}
public class ConcreteComponent extends BaseComponent {
    private BehaviorContract behavior;
    public void performAction() {
        behavior.execute();
    }
}
CompositeComponent composition

CompositeComponent composes multiple BaseComponent instances in a thread-safe list with synchronized add/remove methods, owning their lifecycle (composition).

🎯 Tests whether candidate understands composition lifecycle ownership and synchronized methods ensure thread-safe mutation of components list.
public class CompositeComponent extends BaseComponent {
    private final List<BaseComponent> components = new ArrayList<>();
    public synchronized void addComponent(BaseComponent c) {
        components.add(c);
    }
    public synchronized void removeComponent(BaseComponent c) {
        components.remove(c);
    }
}
Client association with BaseComponent

Client holds a reference to BaseComponent via association (not composition), indicating independent lifecycle and usage without ownership.

🎯 Tests if candidate distinguishes association from composition and understands Client depends on abstraction BaseComponent for flexibility.
public class Client {
    private BaseComponent component;
    public void run() {
        // Use component polymorphically
    }
}
📐
Class Diagram
Class Diagram
       +----------------------+
       | <<Abstract>>         |
       | BaseComponent        |
       |----------------------|
       | - id: String          |
       | - volatile active:bool|
       |----------------------|
       | + synchronized void   |
       |   activate()          |
       | + synchronized void   |
       |   deactivate()        |
       +----------------------+
               │ extends
       +----------------------+
       | ConcreteComp.        |
       |----------------------|
       | - behavior: BehaviorContract |
       |----------------------|
       | + void performAction()|
       +----------------------+
               │
               │ composition ◆
       +----------------------+
       | CompositeComp.       |
       |----------------------|
       | - components: List<BaseComponent> |
       |----------------------|
       | + synchronized void   |
       |   addComponent(BaseComponent) |
       | + synchronized void   |
       |   removeComponent(BaseComponent) |
       +----------------------+
               ─ ─ ─► realization
       +----------------------+
       | <<Interface>>        |
       | BehaviorContract     |
       |----------------------|
       | + void execute()     |
       +----------------------+
               ─ ─ ─► association
       +----------------------+
       | Client                |
       |----------------------|
       | - component: BaseComponent |
       |----------------------|
       | + void run()          |
       +----------------------+

This diagram illustrates key Java OOP design decisions for choosing inheritance versus composition. BaseComponent is an abstract class holding shared mutable state with volatile and synchronized methods to ensure thread safety and visibility. BehaviorContract is an interface used to define behavior without state, enabling the Strategy pattern and adhering to the Open-Closed Principle by allowing behavior extension without modifying ConcreteComponent. CompositeComponent uses composition to own multiple BaseComponent instances, managing their lifecycle with synchronized methods to prevent concurrent modification bugs. Client associates with BaseComponent via association, showing dependency without ownership, promoting flexibility and loose coupling. These decisions demonstrate Java-specific mechanisms like volatile, synchronized, abstract classes for state, and interfaces for behavior contracts.

Primary Focus

✓ Abstract class state vs interface behavior + Composition lifecycle + Strategy pattern OCP + Template Method reuse

Practice

(1/5)
1. In the Online Auction System, the AuctionManager class has a private constructor and a static synchronized getInstance() method. Which design pattern is applied here and why is this the correct choice?
easy
A. Singleton pattern, to ensure only one AuctionManager instance manages all auctions globally.
B. Factory pattern, because it controls object creation centrally for different auction types.
C. Builder pattern, to incrementally construct complex AuctionManager configurations.
D. Prototype pattern, to clone AuctionManager instances for each auction session.

Solution

  1. Step 1: Identify Singleton intent

    The private constructor and static synchronized getInstance() method ensure only one instance of AuctionManager exists, centralizing auction state management.
  2. Step 2: Eliminate other patterns

    Factory creates multiple objects, Builder incrementally builds complex objects, Prototype clones instances--none enforce single global instance.
  3. Final Answer:

    Option A -> Option A
  4. Quick Check:

    Private constructor + synchronized getInstance() -> Singleton pattern [check]
Hint: Private constructor + static getInstance() -> Singleton [check]
Common Mistakes:
2. You want to add a WeekendFeeStrategy to calculate parking fees differently on weekends using the current adapter-based design. What is the minimum change required to comply with SOLID principles?
medium
A. Add a boolean flag to Vehicle to indicate weekend and modify ParkingLot to check it.
B. Create a new WeekendFeeStrategy class implementing FeeStrategy and inject it where needed without modifying existing classes.
C. Modify the existing FeeStrategy class to add weekend logic with if-else checks.
D. Add weekend fee logic inside the adapter class that adapts Vehicle to ParkingLot.

Solution

  1. Step 1: Identify SOLID principle involved

    Open-Closed Principle (OCP) requires extending behavior without modifying existing code.
  2. Step 2: Evaluate options

    Create a new WeekendFeeStrategy class implementing FeeStrategy and inject it where needed without modifying existing classes. respects OCP by adding a new class implementing FeeStrategy. Add a boolean flag to Vehicle to indicate weekend and modify ParkingLot to check it. modifies Vehicle and ParkingLot, violating OCP. Options A and D modify existing classes.
  3. Final Answer:

    Option A -> Option A
  4. Quick Check:

    New strategy class extends behavior without modifying existing code [check]
Hint: OCP: extend with new class, don't modify existing ones [check]
Common Mistakes:
3. In a multi-threaded environment, if the addProductToCart() method is not synchronized, which exact sequence of events can cause the cart to contain duplicate entries for the same product?
medium
A. Thread 1 checks if product exists -> false, context switch; Thread 2 checks -> false; both add product concurrently.
B. Thread 1 adds product, Thread 2 removes product simultaneously causing inconsistency.
C. Thread 1 updates quantity, Thread 2 reads stale quantity due to lack of volatile keyword.
D. Thread 1 locks cart, Thread 2 waits but eventually overwrites product quantity.

Solution

  1. Step 1: Identify check-then-act race condition

    Both threads check if product exists and see false before either adds it, due to lack of synchronization.
  2. Step 2: Both threads add product concurrently causing duplicates

    Because the add operation is not atomic, both add the product, resulting in duplicates.
  3. Final Answer:

    Option A -> Option A
  4. Quick Check:

    Check-then-act gap without synchronization -> duplicate entries [check]
Hint: Check-then-act gap -> duplicate add without sync [check]
Common Mistakes:
4. In the OrderBook class, the placeOrder() method checks if the order slot is available and then books it. Without synchronization on placeOrder(), which exact sequence of thread interleaving causes double-booking of the same slot?
medium
A. Thread 1 reads slot as occupied, Thread 2 reads slot as free, both proceed to book.
B. Thread 1 checks slot availability -> free, context switch before booking; Thread 2 checks slot availability -> free, both book same slot.
C. Thread 1 books slot, Thread 2 waits for lock and then books the same slot after release.
D. Thread 1 and Thread 2 both crash before booking, leaving slot unbooked.

Solution

  1. Step 1: Identify the check-then-act race condition

    Without synchronization, Thread 1 reads slot as free but is preempted before booking; Thread 2 also reads free and proceeds to book.
  2. Step 2: Why this causes double-booking

    Both threads believe the slot is free and book it concurrently, causing inconsistent state and double-booking.
  3. Final Answer:

    Option B -> Option B
  4. Quick Check:

    Check-then-act gap without lock -> double-booking [check]
Hint: Check slot free -> context switch -> both book same slot [check]
Common Mistakes:
5. You need to add ElectricCar support with ChargingSpots to a parking lot system using the State pattern. What is the minimum change to support this without modifying existing classes?
hard
A. Modify Vehicle base class to add isElectric flag and add charging logic in existing Spot classes
B. Create a new ElectricVehicle interface and modify all existing Vehicle subclasses to implement it
C. Add ELECTRIC_CAR to VehicleType enum and CHARGING to SpotType enum, create ElectricCar subclass, update SpotCompatibility map
D. Add charging logic inside the existing State classes handling parking spots

Solution

  1. Step 1: Identify extensibility requirements

    Adding ElectricCar and ChargingSpot requires new types without modifying existing classes to respect OCP.
  2. Step 2: Evaluate options

    Add ELECTRIC_CAR to VehicleType enum and CHARGING to SpotType enum, create ElectricCar subclass, update SpotCompatibility map adds new enum values and subclasses without changing existing classes, enabling extension. Options B, C, and D modify existing classes or interfaces, violating OCP.
  3. Final Answer:

    Option C -> Option C
  4. Quick Check:

    New enums and subclass -> no existing class modified [check]
Hint: Add new enums and subclasses, avoid modifying existing classes [check]
Common Mistakes:
Recommended

Ready to prove it?

Pass the test and this pattern moves unknown strong while earning +1 Grip toward your certificate.

10 questions~5 mineasy hard