Bird
Raised Fist0

Design a Ride Booking Class Hierarchy - Driver, Rider, Trip, Vehicle, Fare Calculation

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

Vehicle is an abstract class holding shared state licensePlate and vehicleType which interfaces cannot hold in Java.

🎯 Tests whether candidate knows abstract class is correct because Vehicle has instance state that interfaces cannot hold in Java.
public abstract class Vehicle {
    private String licensePlate;
    private String vehicleType;
    public String getLicensePlate() { return licensePlate; }
    public String getVehicleType() { return vehicleType; }
}
Trip composition with Vehicle

Trip composes Vehicle (composition) meaning Trip owns Vehicle lifecycle and is responsible for it.

🎯 Tests whether candidate distinguishes composition (Trip owns Vehicle) from association (Driver, Rider) with independent lifecycles.
public class Trip {
    private Driver driver; // association
    private Rider rider;   // association
    private Vehicle vehicle; // composition
    private Fare fare;
    public void startTrip() { /* ... */ }
    public void endTrip() { /* ... */ }
}
FareCalculator interface and SurgeFareCalculator realization

FareCalculator is an interface defining calculateFare method; SurgeFareCalculator realizes it with surgeMultiplier state.

🎯 Tests understanding of Strategy pattern via interface for OCP and realization with concrete class holding state.
public interface FareCalculator {
    double calculateFare(Trip trip);
}
public class SurgeFareCalculator implements FareCalculator {
    private double surgeMultiplier;
    public double calculateFare(Trip trip) {
        // calculate fare with surgeMultiplier
    }
}
Concurrency in Singleton FareCalculator (implied)

If FareCalculator implementations are singletons, volatile is needed on instance to prevent half-constructed objects visible to other threads.

🎯 Tests whether candidate knows volatile keyword is required on singleton instance to prevent JVM reordering and visibility issues.
public class SurgeFareCalculator implements FareCalculator {
    private static volatile SurgeFareCalculator instance;
    private SurgeFareCalculator() { }
    public static SurgeFareCalculator getInstance() {
        if (instance == null) {
            synchronized(SurgeFareCalculator.class) {
                if (instance == null) instance = new SurgeFareCalculator();
            }
        }
        return instance;
    }
    // calculateFare implementation
}
📐
Class Diagram
Class Diagram
       +----------------+
       |    <<Abstract>>|
       |    Vehicle     |
       +----------------+
       | -licensePlate  |
       | -vehicleType   |
       +----------------+
       | +getLicense()  |
       | +getType()     |
       +----------------+
              │
              │
       +----------------+
       |      Trip      |
       +----------------+
       | -driver: Driver|
       | -rider: Rider  |
       | -vehicle: Vehicle ◆
       | -fare: Fare    |
       +----------------+
       | +startTrip()   |
       | +endTrip()     |
       +----------------+
              │
              │
       +----------------------+
       | <<Interface>>        |
       | FareCalculator       |
       +----------------------+
       | +calculateFare(Trip) |
       +----------------------+
              │
              │ ─ ─ ─► realization
       +-------------------------+
       | SurgeFareCalculator     |
       +-------------------------+
       | +calculateFare(Trip)    |
       | -surgeMultiplier        |
       +-------------------------+

This diagram illustrates key Java-specific design decisions in a ride booking system. Vehicle is an abstract class because it holds shared instance state like licensePlate and vehicleType, which interfaces cannot hold in Java. Trip composes Vehicle, indicating Trip owns the Vehicle lifecycle, while Driver and Rider are associated with independent lifecycles. FareCalculator is an interface defining the fare calculation contract, enabling the Strategy pattern for extensibility. SurgeFareCalculator realizes this interface and holds state such as surgeMultiplier. For concurrency safety, if FareCalculator implementations are singletons, the volatile keyword is essential on the instance field to prevent JVM instruction reordering and visibility issues across threads. These decisions enforce SOLID principles and ensure thread-safe extensibility.

Primary Focus

✓ Abstract class vs Interface state + Composition lifecycle + Strategy pattern realization + Java concurrency volatile

Practice

(1/5)
1. In a UML class diagram, should Vehicle be modeled as an abstract class or an interface if it has state like speed and behavior like accelerate()? Why?
easy
A. Interface, because it allows multiple inheritance and defines behavior without state.
B. Abstract class, because it can hold shared state and provide default behavior implementations.
C. Interface, because state can be stored externally and behavior defined via default methods.
D. Abstract class, because interfaces cannot declare methods with parameters.

Solution

  1. Step 1: Analyze state and behavior requirements

    Vehicle has state (speed) and behavior (accelerate()), so it needs a construct that supports instance variables and method implementations.
  2. Step 2: Evaluate abstract class vs interface

    Abstract classes can hold state and provide default behavior; interfaces cannot hold instance state (only constants) and default methods can't maintain state.
  3. Final Answer:

    Option B -> Option B
  4. Quick Check:

    State + behavior with shared code -> abstract class [check]
Hint: Stateful base class -> abstract class, not interface [check]
Common Mistakes:
2. In a multi-threaded parking lot system using Abstract Factory to create vehicles and spots, if parkVehicle() is not synchronized, which exact thread interleaving causes double-booking of the same spot?
medium
A. Thread 1 parks vehicle, Thread 2 parks vehicle after Thread 1 finishes.
B. Thread 1 checks spot availability -> true, context switch; Thread 2 checks spot availability -> true; both park simultaneously.
C. Thread 1 parks vehicle, Thread 2 waits for Thread 1 to release lock before parking.
D. Thread 1 and Thread 2 both fail to find any available spots and abort.

Solution

  1. Step 1: Identify race condition in parkVehicle()

    Without synchronization, two threads can both check spot availability before either marks it occupied.
  2. Step 2: Trace exact interleaving

    Thread 1 calls isAvailable() -> true, context switch before marking occupied; Thread 2 calls isAvailable() -> true; both proceed to park, causing double-booking.
  3. Final Answer:

    Option B -> Option B
  4. Quick Check:

    Check-then-act gap without synchronization causes double-booking [check]
Hint: Check-then-act gap -> both see available, both park [check]
Common Mistakes:
3. The Wallet System currently calculates fees with a FeeStrategy interface. To add a WeekendFeeStrategy without modifying existing classes, which SOLID principle is being applied and what is the minimum required change?
medium
A. Open/Closed Principle: create WeekendFeeStrategy implementing FeeStrategy; no existing class changes.
B. Dependency Inversion Principle: inject WeekendFeeStrategy into Account class by modifying Account.
C. Single Responsibility Principle: modify FeeStrategy to handle weekends explicitly.
D. Liskov Substitution Principle: override FeeStrategy methods in WeekendFeeStrategy and modify Transaction.

Solution

  1. Step 1: Identify the SOLID principle for extensibility

    Open/Closed Principle (OCP) states software entities should be open for extension but closed for modification.
  2. Step 2: Apply OCP to fee calculation

    Adding WeekendFeeStrategy as a new class implementing FeeStrategy extends behavior without modifying existing classes, preserving OCP.
  3. Final Answer:

    Option A -> Option A
  4. Quick Check:

    New FeeStrategy implementation -> no existing class changes -> OCP [check]
Hint: Add new strategy class, no existing code change -> OCP [check]
Common Mistakes:
4. To add a WeekendFeeStrategy for weekend parking fees without modifying existing classes, which SOLID principle is being applied and what is the minimal required change?
medium
A. Single Responsibility Principle; modify ParkingLot to add weekend fee logic.
B. Open-Closed Principle; create a new WeekendFeeStrategy class implementing FeeStrategy and inject it without changing existing code.
C. Dependency Inversion Principle; invert dependencies by making ParkingLot depend on concrete weekend fee classes.
D. Liskov Substitution Principle; override existing fee methods in ParkingLot subclass for weekend fees.

Solution

  1. Step 1: Identify SOLID principle

    Open-Closed Principle (OCP) requires extending behavior without modifying existing classes.
  2. Step 2: Apply minimal change

    Create new WeekendFeeStrategy implementing FeeStrategy and inject it; no existing class changes needed.
  3. Final Answer:

    Option B -> Option B
  4. Quick Check:

    OCP: new fee class added, existing classes unchanged [check]
Hint: OCP: extend with new class, no existing code changes [check]
Common Mistakes:
5. You need to add support for ElectricCar and ChargingSpot in the existing parking system using the Iterator pattern. What is the minimum change to the current design to support this without modifying existing classes?
hard
A. Modify Vehicle and Spot classes to include electric-specific fields and logic, then update iterators accordingly.
B. Add ELECTRIC_CAR to VehicleType enum, CHARGING to SpotType enum, create ElectricCar subclass, and update SpotCompatibility map; existing classes remain unchanged.
C. Create a new ElectricVehicle interface extending Vehicle and a ChargingSpot class, then modify existing iterators to handle them.
D. Add a flag isElectric to Vehicle class and modify SpotCompatibility to check this flag during iteration.

Solution

  1. Step 1: Identify extensibility requirements

    Adding ElectricCar and ChargingSpot should not require modifying existing classes to respect OCP.
  2. Step 2: Evaluate options

    Add ELECTRIC_CAR to VehicleType enum, CHARGING to SpotType enum, create ElectricCar subclass, and update SpotCompatibility map; existing classes remain unchanged. adds new enums and classes without modifying existing ones, preserving OCP. Modify Vehicle and Spot classes to include electric-specific fields and logic, then update iterators accordingly. modifies existing classes, violating OCP. Create a new ElectricVehicle interface extending Vehicle and a ChargingSpot class, then modify existing iterators to handle them. adds interfaces but requires modifying iterators, violating OCP. Add a flag isElectric to Vehicle class and modify SpotCompatibility to check this flag during iteration. modifies Vehicle class, violating OCP.
  3. Final Answer:

    Option A -> Option A
  4. Quick Check:

    Adding new enums and subclasses without changing existing classes respects OCP [check]
Hint: Add new types via enums and subclasses, no existing class changes [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