Bird
Raised Fist0

Interface vs Abstract Class - When Each Is the Right Choice

LLDmediumInterview freq: high
Choose your preparation mode4 modes available
๐ŸŽฏ
Interface vs Abstract Class - When Each Is the Right Choice
40 min ยท medium
medium

Design a parking lot system with 5 levels and 4 gates. Vehicles of different types (Car, Bike, Truck) park in spots with pricing based on spot type and duration. The system must handle concurrent parking requests and support extensibility for new vehicle types and pricing strategies.

  • Vehicle types include Car, Bike, and Truck, each with unique attributes.
  • Parking spots have types (Compact, Large, Handicapped) affecting pricing.
  • Pricing depends on spot type and duration parked.
  • Concurrent parking requests can occur at multiple gates.
  • The system should allow adding new vehicle types without modifying existing code.
๐Ÿ“‹
Guided Steps
1/5
Step 1
Define Vehicle abstraction
Design the Vehicle abstraction capturing common state and behavior for all vehicle types.
๐Ÿ’ก Hint
Use an abstract class if you need to hold instance fields like licensePlate and vehicleType; interfaces cannot hold state in Java.
abstract class Vehicle with fields licensePlate (String) and vehicleType (enum VehicleType) - abstract because it holds shared instance STATE; interface cannot hold fields in Java.
Mid: Recognizes abstract class for shared state and behavior. Senior: Explains why interface cannot hold instance fields and how abstract class enables code reuse and encapsulation.
โš ๏ธCommon Wrong Answer
Using interface Vehicle with default methods but no fields leads to duplicated state in subclasses and violates DRY principle.
Step 2
Define SpotType and VehicleType enums
Model spot types and vehicle types to avoid runtime errors and improve type safety.
๐Ÿ’ก Hint
Use Java enums for SpotType and VehicleType to get compile-time checking and exhaustive switch support.
Use enum SpotType {COMPACT, LARGE, HANDICAPPED} and enum VehicleType {CAR, BIKE, TRUCK} - enums provide type safety and prevent typo bugs unlike Strings.
Mid: Uses enums instead of Strings. Senior: Explains how enums enable exhaustive switch and IDE refactoring support, preventing runtime bugs.
โš ๏ธCommon Wrong Answer
Using String constants for types causes silent runtime bugs due to typos and no compile-time validation.
Step 3
Design Pricing strategy abstraction
Design how pricing is calculated based on spot type and duration, allowing future pricing strategies.
๐Ÿ’ก Hint
Use interface PricingStrategy with method calculatePrice(SpotType spotType, Duration duration) to allow multiple implementations.
interface PricingStrategy with method double calculatePrice(SpotType spotType, Duration duration) - interface used because no shared state is needed, only behavior contract.
Mid: Defines interface for pricing strategy. Senior: Explains interface suits stateless behavior contracts and enables Open/Closed Principle for adding new pricing without modifying existing code.
โš ๏ธCommon Wrong Answer
Using abstract class for PricingStrategy with no fields wastes memory and reduces flexibility for stateless strategies.
Step 4
Handle concurrency in parking operations
Ensure thread-safe parking spot allocation when multiple gates process requests concurrently.
๐Ÿ’ก Hint
Use synchronized methods or locks on parkVehicle(Vehicle v) to atomically check and set spot availability; volatile alone is insufficient for atomicity.
public synchronized boolean parkVehicle(Vehicle v) in ParkingSpot to atomically check isAvailable and set to occupied - synchronized ensures atomicity and visibility; volatile alone cannot guarantee atomic check-and-set.
Mid: Uses synchronized to prevent race conditions. Senior: Explains exact thread interleaving where without synchronized, two threads read isAvailable=true and both park, causing double booking.
โš ๏ธCommon Wrong Answer
Using volatile boolean isAvailable without synchronization leads to race condition where multiple threads park in the same spot.
Step 5
Extensibility for new vehicle types
Design so new vehicle types can be added without modifying existing Vehicle or ParkingSpot classes.
๐Ÿ’ก Hint
Use interface VehicleType and abstract class Vehicle to separate state and behavior; new types extend Vehicle and implement VehicleType enum extension or use composition.
abstract class Vehicle with protected constructor and VehicleType enum; new vehicle types extend Vehicle and add specific fields - Open/Closed Principle enforced by inheritance and enum extension.
Mid: Adds new subclass extending Vehicle. Senior: Explains how abstract class holding state enables extension without modifying base class, and enum extension requires careful versioning.
โš ๏ธCommon Wrong Answer
Modifying existing Vehicle class to add new types violates Open/Closed Principle and risks regression bugs.
๐Ÿ”Œ
API Design Challenge
Design the APIs for parking vehicles, querying spot availability, and calculating pricing, ensuring thread safety and extensibility.
  • Use synchronized methods or locks to handle concurrent parking requests safely.
  • Define clear interfaces for pricing strategies to allow dynamic injection of new pricing rules.
  • Use enums for vehicle and spot types to enable exhaustive switch statements and prevent runtime errors.
๐Ÿ“Š
Scoring Rubric
โ–ผ Show
Must Have - 60%
  • abstract class Vehicle with instance fields licensePlate and vehicleType
  • enum VehicleType and SpotType for type safety
  • interface PricingStrategy for stateless behavior
  • synchronized parkVehicle method for atomic spot allocation
  • explanation why volatile alone is insufficient for atomicity
Good to Have - 30%
  • Open/Closed Principle adherence in Vehicle extension
  • composition relationship between ParkingLot, Levels, and Spots with lifecycle ownership
  • explanation of happens-before guarantees from synchronized
  • use of enums enabling exhaustive switch statements
  • clear separation of interface vs abstract class based on state vs behavior
Bonus - 10%
  • discussion of double-checked locking with volatile for singleton ParkingLot
  • examples of concurrency bugs from missing synchronization
  • explanation of how interface default methods differ from abstract class methods
  • design allowing dynamic pricing strategy injection
  • thread interleaving scenarios illustrating race conditions
Using String for VehicleType or SpotType leads to silent runtime bugs due to typos and no compile-time validation, causing unexpected behavior at runtime.
Using volatile boolean isAvailable without synchronization causes race conditions allowing double booking because volatile ensures visibility but not atomicity of check-and-set operations.
โœ…
Model Answer
โ–ผ Reveal

This design differentiates when to use interface versus abstract class in Java by focusing on instance state and behavior sharing. Vehicle is an abstract class holding shared state like licensePlate and vehicleType, enabling code reuse and encapsulation. PricingStrategy is an interface representing stateless behavior contracts, allowing multiple pricing implementations. Enums are used for VehicleType and SpotType to ensure type safety and prevent runtime errors. ParkingSpot's parkVehicle method is synchronized to ensure atomic allocation and prevent race conditions in concurrent environments. The design supports extensibility by allowing new vehicle types to extend Vehicle without modifying existing code, adhering to the Open/Closed Principle.

  • Use abstract class Vehicle to hold instance state licensePlate and vehicleType because interfaces cannot hold state in Java.
  • Use enums for VehicleType and SpotType to enable compile-time type safety and exhaustive switch statements.
  • Define PricingStrategy as an interface since pricing calculation is stateless behavior, allowing multiple implementations.
  • Synchronize parkVehicle method in ParkingSpot to atomically check availability and assign spot, preventing race conditions.
  • Avoid volatile alone for isAvailable flag because it does not guarantee atomic check-and-set; synchronized is required.
  • Enforce Open/Closed Principle by allowing new vehicle types to extend Vehicle without modifying existing classes.
  • Use composition to model ParkingLot containing ParkingLevels and ParkingSpots, ensuring lifecycle ownership.
  • Use synchronized methods to establish happens-before relationships, ensuring visibility of state changes across threads.
  • abstract class Vehicle holds licensePlate and vehicleType fields - interfaces cannot hold instance state in Java.
  • Use enum for VehicleType and SpotType to ensure compile-time type safety and prevent runtime typo bugs.
  • PricingStrategy defined as interface because it represents stateless behavior contract without instance fields.
  • ParkingSpot parkVehicle method synchronized to atomically check and set availability, preventing race conditions.
  • volatile alone is insufficient for atomic check-and-set operations; synchronized is required for thread safety.
  • Open/Closed Principle enforced by abstract Vehicle class allowing extension without modification.
  • Composition used for ParkingLot containing ParkingLevels and ParkingSpots with lifecycle ownership - spots cannot exist independently.
  • Use of synchronized methods ensures happens-before relationship guaranteeing visibility of state changes across threads.
  • Avoid String constants for types to prevent silent runtime errors; enums provide exhaustive switch and IDE support.
  • Separate interface and abstract class usage based on whether instance state is needed (abstract class) or only behavior contract (interface).

Practice

(1/5)
1. A class CarBuilder constructs a Car object step-by-step using methods like setEngine(), setWheels(), and finally build(). The Car constructor is private. Which design pattern is applied here and why is it the correct choice?
easy
A. Builder pattern, because it separates complex object construction from its representation, allowing stepwise creation.
B. Factory Method pattern, because it creates objects through inheritance and subclasses.
C. Prototype pattern, because it clones existing objects to create new ones efficiently.
D. Singleton pattern, because it ensures only one instance of Car exists.

Solution

  1. Step 1: Identify the construction process

    The class uses multiple setter methods to configure parts of the object before finalizing with build(), indicating stepwise construction.
  2. Step 2: Match pattern intent

    Builder pattern separates construction from representation, ideal for complex objects with many optional parts. Factory Method uses inheritance, Prototype clones objects, Singleton restricts instance count.
  3. Final Answer:

    Option A -> Option A
  4. Quick Check:

    Stepwise object creation with private constructor -> Builder pattern [check]
Hint: Stepwise construction with private constructor -> Builder pattern [check]
Common Mistakes:
2. In designing the traffic light system, should Vehicle be an abstract class or an interface, considering vehicles have state like speed and direction? Why?
easy
A. Vehicle should be an interface because it only defines behavior without state
B. Vehicle should be an interface with default methods to hold state
C. Vehicle should be an abstract class to encapsulate shared state and behavior
D. Vehicle should be a final class to prevent subclassing and ensure immutability

Solution

  1. Step 1: Analyze state vs behavior requirements

    Vehicles have shared state (speed, direction) and behavior; interfaces cannot hold instance state, so interface alone is insufficient.
  2. Step 2: Abstract class encapsulates shared state and common methods

    Abstract class allows shared fields and partial implementation, enabling subclasses to extend and customize behavior.
  3. Final Answer:

    Option C -> Option C
  4. Quick Check:

    Stateful base class -> abstract class, not interface [check]
Hint: Stateful base class -> abstract class, stateless -> interface [check]
Common Mistakes:
3. In designing the Wallet System, should the Account class be an abstract class or an interface, considering it holds state like balance and transaction history? Why?
easy
A. Interface, because it enforces method signatures without implementation, suitable for stateful classes.
B. Abstract class, because it prevents multiple inheritance issues common with interfaces.
C. Interface, because Java interfaces can now hold state with default methods.
D. Abstract class, because it allows sharing state and common behavior like balance management across subclasses.

Solution

  1. Step 1: Analyze state and behavior requirements

    The Account class holds mutable state (balance, transaction history) and common behavior (debit, credit), which requires shared implementation and fields.
  2. Step 2: Abstract class vs interface for stateful behavior

    Interfaces cannot hold instance state (fields), only constants and default methods without backing fields. Abstract classes allow fields and method implementations, making them suitable for shared state and behavior.
  3. Final Answer:

    Option D -> Option D
  4. Quick Check:

    Stateful class with shared behavior -> Abstract class [check]
Hint: State + behavior shared -> abstract class, not interface [check]
Common Mistakes:
4. In a multi-threaded command queue, if the execute() method is not synchronized, which exact sequence of events can cause the same command to be executed twice concurrently?
medium
A. Thread 1 and Thread 2 both call execute() simultaneously and both complete successfully
B. Thread 1 and Thread 2 deadlock waiting for each other's locks
C. Thread 1 finishes execute(), but Thread 2 never sees the updated executed flag due to visibility issues
D. Thread 1 checks if command is not executed, context switch before marking executed; Thread 2 checks same and executes again

Solution

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

    Without synchronization, Thread 1 reads executed=false, then context switches before setting executed=true.
  2. Step 2: Thread 2 reads executed=false and proceeds to execute again

    Both threads execute the command concurrently, causing double execution.
  3. Final Answer:

    Option D -> Option D
  4. Quick Check:

    Unsynchronized check-then-act allows double execution [check]
Hint: Unsynchronized check-then-act causes double execution [check]
Common Mistakes:
5. Adding a WeekendFeeStrategy to the current parking fee system requires which minimum change to comply with SOLID principles?
medium
A. Add a boolean flag isWeekend in ParkingLot and conditionally apply fees inside existing strategies.
B. Create a new WeekendFeeStrategy class implementing FeeStrategy without modifying existing classes.
C. Modify the existing FeeStrategy interface to add a isWeekend() method and update all implementations.
D. Combine all fee strategies into one class with conditional logic for weekends.

Solution

  1. Step 1: Identify applicable SOLID principle

    The Open/Closed Principle (OCP) requires that classes be open for extension but closed for modification.
  2. Step 2: Evaluate options against OCP

    Create a new WeekendFeeStrategy class implementing FeeStrategy without modifying existing classes. respects OCP by adding a new class without modifying existing ones. Add a boolean flag isWeekend in ParkingLot and conditionally apply fees inside existing strategies. violates OCP by modifying ParkingLot and existing strategies with conditional logic.
  3. Final Answer:

    Option A -> Option A
  4. Quick Check:

    New strategy class added, existing code unchanged -> OCP respected [check]
Hint: Add new strategy class, don't modify existing ones [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