Bird
Raised Fist0

Facade Pattern - Simplifying Complex Subsystems for Clients

LLDeasyInterview freq: common
Choose your preparation mode4 modes available
๐ŸŽฏ
Facade Pattern - Simplifying Complex Subsystems for Clients
40 min ยท medium
medium

A parking facility has 5 levels, each with 4 gates. Each gate controls entry and exit. Pricing depends on vehicle type and duration. Clients should interact with a simple Facade interface to park and retrieve vehicles without dealing with subsystem complexities.

  • There are 5 levels and 4 gates per level, each gate manages entry and exit independently.
  • Pricing varies by vehicle type (Car, Bike, Truck) and parking duration.
  • Subsystems include GateControl, LevelManagement, and Pricing modules.
  • Concurrency is expected as multiple vehicles can enter/exit simultaneously.
  • Clients must not interact directly with subsystems but through a unified Facade.
๐Ÿ“‹
Guided Steps
1/5
Step 1
Define Vehicle Types Using Enum
Design a VehicleType enum to represent different vehicle categories for pricing and parking logic.
๐Ÿ’ก Hint
Use Java enum to ensure type safety and exhaustive switch-case handling.
Use enum VehicleType {CAR, BIKE, TRUCK} - enums provide compile-time safety and prevent runtime typo bugs unlike String constants.
Mid: Recognizes enum as pattern for fixed set of constants. Senior: Explains how enum enables exhaustive switch and IDE support preventing runtime errors.
โš ๏ธCommon Wrong Answer
Using String constants for vehicle types leads to runtime bugs due to typos and no compile-time checks.
Step 2
Design Abstract Vehicle Class with State
Create an abstract Vehicle class holding licensePlate and VehicleType fields, to be extended by concrete vehicle classes.
๐Ÿ’ก Hint
Use abstract class because it holds instance state; interfaces cannot hold fields in Java.
abstract class Vehicle with private final String licensePlate and final VehicleType vehicleType - abstract because it holds instance state which interfaces cannot in Java.
Mid: Uses abstract class for shared state. Senior: Explains why interface cannot hold fields and how abstract class enforces common behavior and state.
โš ๏ธCommon Wrong Answer
Using interface for Vehicle with fields is invalid in Java and leads to compilation errors.
Step 3
Implement Facade Class with Synchronized Methods
Design a ParkingFacade class exposing parkVehicle and retrieveVehicle methods that internally coordinate subsystems.
๐Ÿ’ก Hint
Use synchronized on parkVehicle and retrieveVehicle to atomically check and update parking state to prevent race conditions.
public synchronized boolean parkVehicle(Vehicle v) - synchronized ensures atomic check-and-set of parking availability preventing concurrent double-booking.
Mid: Identifies Facade pattern to simplify client interface. Senior: Traces thread interleaving where without synchronized, two threads read availability simultaneously causing double-booking.
โš ๏ธCommon Wrong Answer
Omitting synchronization leads to race conditions where multiple threads park vehicles in the same spot simultaneously.
Step 4
Use Volatile for Singleton Instance in Subsystem
Implement a singleton LevelManager to manage parking levels ensuring thread-safe lazy initialization.
๐Ÿ’ก Hint
Use volatile LevelManager instance with double-checked locking to prevent partially constructed objects being visible to other threads.
private static volatile LevelManager instance; double-checked locking in getInstance() - volatile prevents JVM reordering and visibility issues.
Mid: Uses Singleton pattern for LevelManager. Senior: Explains how without volatile, JVM may return partially constructed instance causing subtle bugs.
โš ๏ธCommon Wrong Answer
Singleton without volatile can cause other threads to see a partially constructed object leading to NullPointerExceptions.
Step 5
Separate Pricing Strategy Using Interface
Design a PricingStrategy interface with method calculatePrice(Vehicle v, Duration d) to allow extensible pricing rules.
๐Ÿ’ก Hint
Use interface for PricingStrategy because it defines behavior without state; concrete classes implement different pricing algorithms.
interface PricingStrategy with method double calculatePrice(Vehicle v, Duration d) - interface used because no shared state is needed, enabling Open/Closed principle.
Mid: Recognizes Strategy pattern for pricing. Senior: Explains interface enables multiple implementations without modifying existing code (Open/Closed principle).
โš ๏ธCommon Wrong Answer
Using abstract class with state for PricingStrategy limits extensibility and violates Open/Closed principle.
๐Ÿ”Œ
API Design Challenge
Design a simple and thread-safe API for clients to park and retrieve vehicles using the Facade pattern, hiding the complexity of multiple levels and gates.
  • Use synchronized methods or blocks in the Facade to handle concurrent access.
  • Expose only essential methods like parkVehicle and retrieveVehicle in the Facade.
  • Ensure pricing calculation is extensible and decoupled from parking logic.
๐Ÿ“Š
Scoring Rubric
โ–ผ Show
Must Have - 60%
  • enum VehicleType for type safety
  • abstract class Vehicle with instance state
  • synchronized methods in Facade to prevent race conditions
  • volatile singleton instance with double-checked locking
  • interface PricingStrategy for extensibility
Good to Have - 30%
  • final fields in Vehicle for immutability
  • composition relationships with clear lifecycle ownership
  • Facade pattern usage to hide subsystem complexity
  • explanation of thread interleaving causing race conditions
  • Open/Closed principle adherence in pricing design
Bonus - 10%
  • detailed concurrency scenario tracing
  • use of Duration class for parking time
  • extensible gate and level management design
  • unit testability considerations
  • clear separation of concerns in subsystem classes
Using String for VehicleType leads to runtime typo bugs and no exhaustive switch-case checking, causing runtime errors and maintenance issues.
Implementing Vehicle as interface with fields causes compilation errors in Java, preventing code from compiling.
Omitting synchronization on parking methods causes race conditions and double-booking, leading to inconsistent parking state.
Singleton without volatile can return partially constructed objects causing NullPointerExceptions and subtle bugs.
Using abstract class with state for PricingStrategy violates Open/Closed principle and reduces extensibility, making pricing changes error-prone.
โœ…
Model Answer
โ–ผ Reveal

The design uses the Facade pattern to provide a simple interface (ParkingFacade) for clients to park and retrieve vehicles without dealing with subsystem complexities. It manages concurrency, state, and extensibility using Java-specific constructs.

  • Use enum VehicleType to prevent runtime errors from string typos and enable exhaustive switch-case.
  • Abstract Vehicle class holds immutable state; interfaces cannot hold fields in Java.
  • Synchronize parkVehicle and retrieveVehicle methods in ParkingFacade to ensure atomic operations and prevent double-booking.
  • Implement LevelManager singleton with volatile instance and double-checked locking to avoid partially constructed instances.
  • Define PricingStrategy as interface to allow multiple pricing implementations adhering to Open/Closed principle.
  • Facade pattern hides subsystem complexity and provides a unified, thread-safe interface to clients.
  • Use final fields in Vehicle to improve thread safety by making key state immutable after construction.
  • Avoid exposing subsystem classes directly to clients to maintain encapsulation and reduce coupling.
  • Use enum VehicleType to represent fixed vehicle categories ensuring compile-time safety.
  • abstract class Vehicle holds licensePlate and vehicleType fields - interfaces cannot hold instance state in Java.
  • ParkingFacade exposes synchronized parkVehicle and retrieveVehicle methods to atomically manage parking state and prevent race conditions.
  • LevelManager singleton uses volatile instance with double-checked locking to ensure thread-safe lazy initialization.
  • PricingStrategy interface defines pricing behavior without state, enabling multiple pricing implementations adhering to Open/Closed principle.
  • Subsystem classes (GateControl, LevelManagement, Pricing) are composed within ParkingFacade, enforcing composition and lifecycle ownership.
  • Use synchronized blocks or methods to protect shared mutable state in concurrent scenarios, preventing interleaving bugs.
  • Facade pattern simplifies client interaction by hiding subsystem complexity and enforcing a unified interface.
  • Use final fields in Vehicle to ensure immutability of key state after construction, improving thread safety.
  • Avoid exposing subsystem classes directly to clients to maintain encapsulation and reduce coupling.

Practice

(1/5)
1. In a Music Streaming Library design, a Playlist class has a private constructor and a static synchronized getInstance() method that returns 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. Builder pattern, to construct complex Playlist objects step-by-step.
C. Prototype pattern, to clone existing Playlist instances efficiently.
D. Singleton pattern, to ensure only one Playlist instance manages the playback queue globally.

Solution

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

    This is the Singleton pattern, which restricts instantiation to one object and provides a global access point.
  2. Step 2: Why Singleton fits Playlist playback queue management

    Since the playback queue must be globally consistent and unique per user session, Singleton ensures only one instance manages it, avoiding conflicting states.
  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:
2. In the Elevator System design, the ElevatorController class uses a private constructor and a static synchronized getInstance() method to provide a single global access point. Which design pattern is applied here and why is it the correct choice?
easy
A. Factory pattern, because it creates ElevatorController instances on demand.
B. Singleton pattern, to ensure only one ElevatorController manages all elevators centrally.
C. Builder pattern, to incrementally construct ElevatorController with complex configuration.
D. Prototype pattern, to clone ElevatorController for each elevator instance.

Solution

  1. Step 1: Identify Singleton usage

    The private constructor and static synchronized getInstance() method restrict instantiation to one object, ensuring a single ElevatorController.
  2. Step 2: Why Singleton fits ElevatorController

    ElevatorController coordinates multiple elevators and floor queues centrally, so multiple instances would cause inconsistent state and scheduling conflicts.
  3. Final Answer:

    Option B -> Option B
  4. Quick Check:

    Singleton ensures one global ElevatorController instance [check]
Hint: Singleton restricts to one instance for centralized control [check]
Common Mistakes:
3. In the ESPNcricinfo system, the Match class has a private constructor and a static synchronized getInstance() method to ensure only one instance per match ID exists. Which design pattern is applied here and why is this the correct use case?
easy
A. Singleton Pattern, because it ensures a single instance per match ID with thread safety.
B. Factory Pattern, because it creates objects based on input parameters.
C. Builder Pattern, because it separates construction and representation of Match objects.
D. Prototype Pattern, because it clones existing Match instances to avoid new creation.

Solution

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

    The private constructor prevents direct instantiation, and the static synchronized getInstance() ensures controlled, thread-safe instance creation.
  2. Step 2: Why Singleton fits this use case

    Singleton ensures only one Match instance per match ID exists, avoiding inconsistent state across threads.
  3. Final Answer:

    Option A -> Option A
  4. Quick Check:

    Private constructor + synchronized getInstance() -> Singleton pattern [check]
Hint: Private constructor + synchronized getInstance() -> Singleton [check]
Common Mistakes:
4. To support ElectricCar and ChargingSpot in the existing parking system using Chain of Responsibility, what is the minimum change that respects extensibility and avoids modifying existing classes?
hard
A. Add ELECTRIC_CAR to VehicleType enum, CHARGING to SpotType enum, create ElectricCar subclass, and update SpotCompatibility.COMPATIBILITY_MAP accordingly.
B. Modify Vehicle and Spot classes to add boolean isElectric and isChargingSpot flags, then update existing handlers to check these flags.
C. Create a new ElectricCarHandler in the chain that handles electric cars and charging spots, modifying the chain setup to include it.
D. Add a new method in Vehicle interface for charging compatibility and implement it in ElectricCar, modifying existing handlers to call it.

Solution

  1. Step 1: Identify extensibility requirements

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

    Add ELECTRIC_CAR to VehicleType enum, CHARGING to SpotType enum, create ElectricCar subclass, and update SpotCompatibility.COMPATIBILITY_MAP accordingly. modifies enums and compatibility map, changing existing code; Modify Vehicle and Spot classes to add boolean isElectric and isChargingSpot flags, then update existing handlers to check these flags. adds flags and updates handlers without changing existing class hierarchies; Create a new ElectricCarHandler in the chain that handles electric cars and charging spots, modifying the chain setup to include it. modifies chain setup, which is acceptable but may require modifying chain initialization; Add a new method in Vehicle interface for charging compatibility and implement it in ElectricCar, modifying existing handlers to call it. modifies Vehicle interface, breaking existing implementations.
  3. Step 3: Choose minimal invasive approach

    Modify Vehicle and Spot classes to add boolean isElectric and isChargingSpot flags, then update existing handlers to check these flags. adds minimal changes with flags and updates handlers, avoiding class explosion or interface changes.
  4. Final Answer:

    Option B -> Option B
  5. Quick Check:

    Flags added, existing classes unchanged, handlers updated [check]
Hint: Add flags and update handlers, avoid modifying classes [check]
Common Mistakes:
5. The messaging system needs to support ElectricCar users who require ChargingSpot delivery locations. What is the minimum change to the current design to support this without modifying existing classes?
hard
A. Modify Vehicle and Spot classes to add electric-specific fields and methods for charging compatibility.
B. Add ELECTRIC_CAR to VehicleType enum, CHARGING to SpotType enum, create ElectricCar subclass, and update SpotCompatibility map externally.
C. Create a new ElectricCar class and ChargingSpot class, then modify existing delivery logic to handle them.
D. Add a boolean isElectric field to Vehicle and a chargingAvailable field to Spot, updating logic accordingly.

Solution

  1. Step 1: Identify extensibility without modifying existing classes

    Adding new enum values and subclasses allows extension without changing existing class code, preserving OCP.
  2. Step 2: Understand how to update compatibility externally

    Updating SpotCompatibility.COMPATIBILITY_MAP externally supports new types without modifying existing logic inside classes.
  3. Final Answer:

    Option B -> Option B
  4. Quick Check:

    Extend enums + subclasses + external map update -> minimal change [check]
Hint: Extend enums and subclasses, update compatibility map externally [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