Bird
Raised Fist0

Template Method Pattern - Defining Algorithm Skeleton, Subclasses Fill In Steps

LLDeasyInterview freq: high
Choose your preparation mode4 modes available
๐ŸŽฏ
Template Method Pattern - Defining Algorithm Skeleton, Subclasses Fill In Steps
40 min ยท medium
medium

Design a multi-level parking lot system with 5 levels and 4 entry/exit gates. The system must calculate parking fees based on vehicle type and duration. The parking process involves common steps like ticket issuance, parking spot allocation, and fee calculation, but subclasses define specific pricing and validation rules.

  • The parking lot has 5 levels and 4 gates (2 entry, 2 exit).
  • Vehicles can be Car, Bike, or Truck, each with different pricing rules.
  • The parking process involves fixed steps: validate vehicle, issue ticket, allocate spot, calculate fee, and release spot.
  • Pricing calculation varies by vehicle type and time of day (day/night rates).
  • Concurrency must be handled for multiple vehicles entering/exiting simultaneously.
๐Ÿ“‹
Guided Steps
1/5
Step 1
Define the Abstract Template Class for Parking Process
Design an abstract class that defines the skeleton of the parking algorithm with concrete and abstract methods representing fixed and variable steps.
๐Ÿ’ก Hint
Use an abstract class with concrete methods for invariant steps and abstract methods for variable steps. Remember, interfaces cannot hold instance state or provide method implementations in Java.
abstract class ParkingProcess with concrete template method parkVehicle() calling abstract steps like validateVehicle(), calculateFee() - abstract class needed because it holds shared instance state and method implementations; interface cannot hold state or method bodies in Java.
Mid: Recognizes Template Method pattern with abstract class defining algorithm skeleton. Senior: Explains why abstract class is chosen over interface due to shared instance state and partial method implementations in Java.
โš ๏ธCommon Wrong Answer
Using interface for Template Method pattern leads to inability to hold shared state or provide default method implementations, forcing code duplication and violating DRY.
Step 2
Implement Concrete Subclasses for Vehicle Types
Create subclasses for Car, Bike, and Truck that implement the variable steps like fee calculation and validation.
๐Ÿ’ก Hint
Override abstract methods from the template class to provide vehicle-specific logic. Use enums for vehicle types to ensure type safety.
Concrete subclasses CarParkingProcess, BikeParkingProcess, TruckParkingProcess override abstract methods; use enum VehicleType to represent vehicle categories ensuring compile-time safety and exhaustive switch checks.
Mid: Identifies subclassing to fill in variable steps. Senior: Explains enum usage prevents runtime bugs from string typos and enables exhaustive switch-case checks by compiler.
โš ๏ธCommon Wrong Answer
Using String constants for vehicle types causes runtime bugs due to typos and no compile-time validation, leading to incorrect fee calculations.
Step 3
Handle Concurrency in Parking Spot Allocation
Design thread-safe methods to allocate and release parking spots to prevent race conditions when multiple vehicles park simultaneously.
๐Ÿ’ก Hint
Use synchronized methods or blocks to atomically check and update spot availability. Consider volatile or AtomicBoolean for spot status to ensure visibility across threads.
public synchronized boolean allocateSpot(ParkingSpot spot) atomically checks isAvailable and sets to occupied; ParkingSpot.isAvailable marked volatile to guarantee visibility; prevents double allocation under concurrent access.
Mid: Names synchronized for thread safety. Senior: Traces race condition where Thread 1 reads isAvailable=true, context switch, Thread 2 reads isAvailable=true, both allocate same spot causing double booking; synchronized prevents this by atomic check-and-set.
โš ๏ธCommon Wrong Answer
Not synchronizing spot allocation leads to race conditions causing multiple vehicles to occupy the same spot, breaking system correctness.
Step 4
Design Pricing Strategy with Template Method Hook
Allow pricing calculation to vary by time of day (day/night) without modifying existing subclasses.
๐Ÿ’ก Hint
Use a hook method in the abstract class that subclasses can override optionally. This supports Open/Closed Principle by enabling extension without modification.
Define protected hook method isNightTime() in abstract class, default returns false; subclasses override to apply night rates; supports Open/Closed Principle by extension without modifying base class.
Mid: Recognizes hook method in Template Method pattern. Senior: Explains how hook enables optional extension points without changing existing code, adhering to Open/Closed Principle.
โš ๏ธCommon Wrong Answer
Hardcoding pricing logic in base class or subclasses violates Open/Closed Principle, requiring code changes for new pricing rules.
Step 5
Model Gate Operations with Composition and Lifecycle Ownership
Design Gate classes representing entry and exit points that interact with the parking process but can exist independently.
๐Ÿ’ก Hint
Use composition to include ParkingProcess in Gate, but Gate and ParkingProcess have independent lifecycles (aggregation).
Gate class aggregates ParkingProcess instance; lifecycle independent since Gate can exist without a specific ParkingProcess; composition avoided to respect lifecycle ownership.
Mid: Identifies aggregation relationship between Gate and ParkingProcess. Senior: Explains lifecycle independence and why composition would incorrectly imply ownership and lifecycle coupling.
โš ๏ธCommon Wrong Answer
Using composition for Gate-ParkingProcess forces ParkingProcess lifecycle tied to Gate, reducing flexibility and violating single responsibility.
๐Ÿ”Œ
API Design Challenge
Design the API for the parking process and gate operations to support extensibility and concurrency. Ensure the API allows adding new vehicle types and pricing rules without modifying existing code.
  • Use abstract classes with template methods to define invariant steps and abstract methods for variable steps.
  • Design thread-safe methods for spot allocation and release using synchronized blocks or methods.
  • Incorporate hook methods to allow optional overrides for pricing strategies like day/night rates.
๐Ÿ“Š
Scoring Rubric
โ–ผ Show
Must Have - 60%
  • abstract class with template method and abstract steps
  • enum for vehicle types to ensure type safety
  • synchronized methods for thread-safe spot allocation
  • volatile keyword for spot availability visibility
Good to Have - 30%
  • hook method for pricing strategy extension
  • aggregation relationship between Gate and ParkingProcess
  • avoid string constants for vehicle types
Bonus - 10%
  • explanation of concurrency issues and synchronization benefits
  • use of Open/Closed Principle in design
โœ…
Model Answer
โ–ผ Reveal

    • abstract class ParkingProcess defines final template method parkVehicle() with concrete and abstract steps; abstract class needed for shared state and partial method implementations.
    • Use enum VehicleType {CAR, BIKE, TRUCK} for type safety and exhaustive switch-case in fee calculation.
    • Concrete subclasses override abstract methods for vehicle-specific validation and fee calculation, adhering to Template Method pattern.
    • ParkingSpot.isAvailable marked volatile boolean to ensure visibility across threads.
    • allocateSpot() and releaseSpot() methods synchronized to atomically check and update spot availability, preventing race conditions.
    • Hook method isNightTime() in abstract class allows subclasses to optionally override pricing logic, supporting Open/Closed Principle.
    • Gate class aggregates ParkingProcess instance; lifecycle independent to allow flexible system composition.
    • Use synchronized on critical methods to prevent double allocation under concurrent vehicle entries.
    • Avoid String constants for types to prevent runtime bugs; enums provide compile-time safety.
    • Template Method pattern enforces invariant algorithm structure while allowing subclass-specific behavior.

    Practice

    (1/5)
    1. A logging framework has a Logger class with a private constructor and a static synchronized getInstance() method returning the single instance. Which design pattern is applied here and why is it the correct choice?
    easy
    A. Factory pattern, because it controls object creation centrally.
    B. Prototype pattern, to clone Logger instances efficiently.
    C. Builder pattern, to construct Logger with complex configurations.
    D. Singleton pattern, ensuring only one Logger instance exists globally.

    Solution

    1. Step 1: Identify the pattern from private constructor and static getInstance()

      The private constructor prevents external instantiation, and the static synchronized getInstance() ensures a single shared instance, which matches the Singleton pattern.
    2. Step 2: Why Singleton is correct here

      Logging frameworks require a single global Logger instance to coordinate log output consistently. Factory, Builder, and Prototype patterns do not enforce single instance semantics.
    3. Final Answer:

      Option D -> Option D
    4. Quick Check:

      Private constructor + static synchronized getInstance() -> Singleton [check]
    Hint: Private constructor + static getInstance() -> Singleton [check]
    Common Mistakes:
    2. In a messaging system design, the Conversation class has a private constructor and a static synchronized getInstance() method that returns the single instance per conversation ID. Which design pattern is applied here and why is this the correct use case?
    easy
    A. Factory pattern, because it creates Conversation objects on demand.
    B. Prototype pattern, to clone existing Conversation instances for new conversations.
    C. Builder pattern, to incrementally construct Conversation objects with optional parameters.
    D. Singleton pattern, ensuring only one Conversation instance per conversation ID exists.

    Solution

    1. Step 1: Identify the pattern from constructor and method

      The private constructor and static synchronized getInstance() method indicate Singleton pattern usage, controlling instance creation.
    2. Step 2: Understand why Singleton fits this use case

      Singleton ensures only one Conversation instance per conversation ID, preventing duplicate conversation objects and maintaining consistent state.
    3. Final Answer:

      Option D -> Option D
    4. Quick Check:

      Private constructor + synchronized getInstance() -> Singleton pattern [check]
    Hint: Private constructor + static getInstance() -> Singleton [check]
    Common Mistakes:
    3. In designing an Observer interface in Java, should it be an abstract class or an interface, and why? Consider that observers only define a single method update() without shared state.
    easy
    A. Use an abstract class to allow future shared state and default method implementations.
    B. Use an interface to allow multiple inheritance and keep observers lightweight without state.
    C. Use an abstract class because interfaces cannot have methods with parameters.
    D. Use an interface because Java interfaces cannot have any method implementations.

    Solution

    1. Step 1: Analyze Observer requirements

      Observers only define update() without shared state, so no need for instance variables or default behavior.
    2. Step 2: Choose interface for flexibility

      Interfaces allow multiple inheritance and keep observers lightweight; abstract classes add unnecessary state and restrict inheritance.
    3. Final Answer:

      Option B -> Option B
    4. Quick Check:

      Observer interface with single method and no state -> interface preferred [check]
    Hint: Observer has no state, so interface enables flexible multiple inheritance [check]
    Common Mistakes:
    4. Given a Vehicle abstraction that requires both state (like speed) and behavior (like accelerate), should Vehicle be an abstract class or an interface in Java, and why?
    easy
    A. Interface, because it allows multiple inheritance and can hold state variables.
    B. Interface, because it can define default methods with state variables initialized.
    C. Abstract class, because it can hold shared state and provide default behavior implementations.
    D. Abstract class, because interfaces cannot define any behavior in Java.

    Solution

    1. Step 1: Analyze state and behavior requirements

      Vehicle needs to hold state like speed and provide behavior like accelerate with shared code, which requires fields and method implementations.
    2. Step 2: Compare abstract class vs interface capabilities

      Abstract classes can have instance variables and concrete methods; interfaces cannot hold instance state (only constants) and default methods cannot maintain state.
    3. Final Answer:

      Option C -> Option C
    4. Quick Check:

      State + behavior with shared code -> abstract class [check]
    Hint: State needs fields? Use abstract class, not interface [check]
    Common Mistakes:
    5. In the auction system, the placeBid() method checks if the auction is still open before accepting a bid. Without synchronizing placeBid(), which exact thread interleaving causes two threads to accept bids after the auction closes, resulting in inconsistent state?
    medium
    A. Thread 1 reads auction open -> false; Thread 2 reads auction open -> true; both reject bids.
    B. Thread 1 and Thread 2 both wait on a lock; no bids accepted until lock released.
    C. Thread 1 writes bid; Thread 2 reads bid; no race condition occurs because writes are atomic.
    D. Thread 1 reads auction open -> true; context switch before bid recorded; Thread 2 reads auction open -> true; both record bids after auction closed.

    Solution

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

      Without synchronization, Thread 1 reads auction open as true but is preempted before recording the bid.
    2. Step 2: Thread 2 reads auction open as true and proceeds to record bid as well, both bypassing the closed state check.

    3. Final Answer:

      Option D -> Option D
    4. Quick Check:

      Unsynchronized check-then-act -> double acceptance after close [check]
    Hint: Check-then-act without sync -> race condition double accept [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