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
Use Facade to provide a unified interface to a set of interfaces in a subsystem, simplifying client interaction.
easyDesign Patterns - AppliedFreq: common
Prerequisites:OOP BasicsUnderstanding of Design PatternsJava Interfaces and Abstract Classes
⚙️
Functional Requirements
  • Provide a single Facade interface to encapsulate multiple subsystem interfaces.
  • Ensure Facade methods coordinate calls to multiple subsystems atomically.
  • Subsystems remain independent and unaware of Facade.
  • Facade should handle exceptions from subsystems and provide unified error handling.
  • Support concurrent access by multiple clients safely.
  • Allow easy extension of subsystems without modifying Facade interface.
  • Facade should not expose subsystem internal details to clients.
👤
Use Cases
  • Client requests a simplified operation that internally coordinates multiple subsystems.
  • Client interacts only with Facade, unaware of subsystem complexities.
  • Subsystems perform their specialized tasks independently.
  • Facade handles error aggregation and reporting to Client.
  • Support concurrent client requests without corrupting subsystem states.
🧑‍💻
Actors
  • Client
  • SubsystemA
  • SubsystemB
  • SubsystemC
  • Facade
❓
Clarifying Questions to Ask
  • How many concurrent client threads are expected to access the Facade simultaneously?
  • Should the Facade support asynchronous operations or only synchronous calls?
  • Are there any specific error handling or retry policies required when subsystems fail?
  • Is there a pricing or cost model affecting subsystem usage or Facade operations?
  • What are the expected edge cases, such as partial subsystem failures or timeouts?
  • Should the Facade be extensible to add new subsystems without modifying existing code?
  • Are subsystem states shared or isolated per client request?
Out of Scope
✗ Subsystem internal implementation details.
✗ Distributed system concerns like network communication.
✗ Persistence or database integration.
✗ Advanced caching or performance optimizations.
🔢
Enumerations
enum OperationStatus
SUCCESS | FAILURE | PARTIAL_SUCCESS
Defines unified operation result states returned by Facade methods, enabling exhaustive switch statements and preventing typo bugs.
enum SubsystemType
SUBSYSTEM_A | SUBSYSTEM_B | SUBSYSTEM_C
Enumerates subsystem identifiers to avoid string literals and enable type-safe subsystem management.
📦
Facade
3 fields
private final SubsystemA subsystemAprivate final SubsystemB subsystemBprivate final SubsystemC subsystemC
Provide a simplified unified interface to clients by coordinating calls to multiple subsystems, handling concurrency and error aggregation.
Why thisFacade pattern is chosen to hide complex subsystem interactions behind a simple interface, improving client usability and reducing coupling.
Why notDirect client calls to subsystems increase complexity and coupling; Mediator pattern is less suitable as it focuses on object communication rather than interface simplification.
public synchronized OperationStatus performComplexOperation()Coordinates calls to all subsystems atomically, returns unified operation status.
public OperationStatus getSubsystemStatus(SubsystemType type)Returns the current status of the specified subsystem.
📦
SubsystemA
1 fields
private volatile boolean isAvailable
Perform specialized operations related to Subsystem A, maintain internal state thread-safely.
Why thisSubsystemA encapsulates specific domain logic; volatile ensures visibility of availability status across threads.
Why notUsing non-volatile fields risks stale reads; external synchronization would complicate design.
public synchronized boolean executeTask()Performs Subsystem A's task atomically, returns success or failure.
public boolean isAvailable()Returns availability status, volatile ensures visibility across threads.
📦
SubsystemB
1 fields
private volatile boolean isAvailable
Perform specialized operations related to Subsystem B, maintain internal state thread-safely.
Why thisSubsystemB encapsulates specific domain logic; volatile ensures visibility of availability status across threads.
Why notUsing non-volatile fields risks stale reads; external synchronization would complicate design.
public synchronized boolean executeTask()Performs Subsystem B's task atomically, returns success or failure.
public boolean isAvailable()Returns availability status, volatile ensures visibility across threads.
📦
SubsystemC
1 fields
private volatile boolean isAvailable
Perform specialized operations related to Subsystem C, maintain internal state thread-safely.
Why thisSubsystemC encapsulates specific domain logic; volatile ensures visibility of availability status across threads.
Why notUsing non-volatile fields risks stale reads; external synchronization would complicate design.
public synchronized boolean executeTask()Performs Subsystem C's task atomically, returns success or failure.
public boolean isAvailable()Returns availability status, volatile ensures visibility across threads.
📦
Client
1 fields
private Facade facade
Invoke Facade methods to perform complex operations without dealing with subsystem complexities.
Why thisClient depends on Facade to reduce complexity and coupling with subsystems.
Why notDirect subsystem interaction increases client complexity and error handling burden.
public void requestOperation()Calls Facade's performComplexOperation and handles the result.
🔗
Relationships
Facade◆──►SubsystemA[1]
compositionFacade owns SubsystemA; SubsystemA cannot exist independently
Facade◆──►SubsystemB[1]
compositionFacade owns SubsystemB; SubsystemB cannot exist independently
Facade◆──►SubsystemC[1]
compositionFacade owns SubsystemC; SubsystemC cannot exist independently
Client──►Facade[1]
associationClient uses Facade but does not own it; Facade exists independently
🗄️
SubsystemStatus
PK: SubsystemType
SubsystemType typeTimestamp timestampOperationStatus status
Stores status history of each subsystem for monitoring and debugging.
🗄️
FacadeOperationLog
PK: OperationId
UUID operationIdTimestamp timestampOperationStatus result
Logs each Facade operation invocation and result for audit and analysis.
🔌
POST /facade/operation
Request
{
  "description": "No body required; triggers performComplexOperation"
}
Response
{
  "status": "200 OK",
  "body": {
    "operationStatus": "SUCCESS | FAILURE | PARTIAL_SUCCESS"
  }
}
Clients invoke this to perform the complex operation via Facade.
🔌
GET /facade/status/{subsystemType}
Request
{
  "parameters": {
    "subsystemType": "SUBSYSTEM_A | SUBSYSTEM_B | SUBSYSTEM_C"
  }
}
Response
{
  "status": "200 OK",
  "body": {
    "operationStatus": "SUCCESS | FAILURE"
  }
}
Returns current availability status of specified subsystem.

Practice

(1/5)
1. In a Card Game Framework, the Deck class has a private constructor and a static synchronized getInstance() method returning the single deck instance. Which design pattern is applied here and why is this the correct choice?
easy
A. Factory Method pattern to create different types of decks dynamically.
B. Singleton pattern to ensure only one deck instance exists across the game.
C. Builder pattern to construct complex deck configurations step-by-step.
D. Prototype pattern to clone decks for multiple players efficiently.

Solution

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

    The private constructor prevents external instantiation, and the static synchronized getInstance() method ensures a single shared instance, matching Singleton pattern characteristics.
  2. Step 2: Why Singleton fits this scenario

    In a card game, having a single deck instance avoids inconsistencies and duplication, ensuring all players draw from the same deck state.
  3. Final Answer:

    Option B -> Option B
  4. Quick Check:

    Private constructor + static synchronized getInstance() -> Singleton [check]
Hint: Private constructor + static getInstance() -> Singleton [check]
Common Mistakes:
2. In designing the Order class, should the OrderState be an abstract class or an interface? Consider that each state has different behavior but shares no common state variables. Which is the best choice and why?
easy
A. Abstract class, because it allows sharing common state variables and default method implementations.
B. Interface, because states only define behavior contracts without shared state, enabling multiple inheritance.
C. Abstract class, because it enforces a fixed inheritance hierarchy and prevents multiple implementations.
D. Interface, because it allows storing state variables in the interface for reuse.

Solution

  1. Step 1: Analyze state sharing needs

    States have no shared variables, only behavior differences, so no need for shared state in a superclass.
  2. Step 2: Evaluate interface vs abstract class

    Interface suits behavior contracts without state and allows flexibility; abstract class is unnecessary and restrictive here.
  3. Final Answer:

    Option B -> Option B
  4. Quick Check:

    Interface fits stateless behavior contracts best [check]
Hint: Interface for behavior-only contracts without shared state [check]
Common Mistakes:
3. You want to add a WeekendFeeStrategy to calculate parking fees differently on weekends. According to SOLID principles, what is the minimum change required in the current Abstract Factory design?
medium
A. Add a boolean weekend flag to ParkingLot and modify fee calculation accordingly.
B. Create a new WeekendFeeStrategy class implementing FeeStrategy and inject it without modifying existing classes.
C. Combine all fee strategies into one class with multiple methods for each pricing rule.
D. Modify the existing FeeStrategy class to add weekend logic with if-else checks.

Solution

  1. Step 1: Identify SOLID principle involved

    Open-Closed Principle (OCP) requires new functionality added via extension, not modification.
  2. Step 2: Evaluate options

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

    Option A -> Option A
  4. Quick Check:

    New strategy class added, existing classes unchanged [check]
Hint: OCP: extend with new class, don't modify existing ones [check]
Common Mistakes:
4. To add a WeekendFeeStrategy for pricing in the current product catalog design, which change respects SOLID principles with minimum modification?
medium
A. Create a new WeekendFeeStrategy class implementing FeeStrategy interface without changing existing classes
B. Modify the existing FeeStrategy class to add weekend logic with if-else
C. Add weekend fee logic inside ProductVariant class directly
D. Add a boolean flag isWeekend in PricingEngine and handle fees there

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: Why creating a new class is best

    Implementing a new WeekendFeeStrategy class extends functionality without modifying existing code, preserving OCP and avoiding side effects.
  3. Final Answer:

    Option A -> Option A
  4. Quick Check:

    New strategy class -> OCP compliance, no existing class changes [check]
Hint: OCP: extend with new class, don't modify existing [check]
Common Mistakes:
5. You need to add support for ElectricCar and ChargingSpot in the card game framework's vehicle parking module. What is the minimum change to the current design to support this without modifying existing classes?
hard
A. Add ELECTRIC_CAR to VehicleType enum, CHARGING to SpotType enum, create ElectricCar subclass, and update compatibility map externally.
B. Modify existing Vehicle and Spot classes to add electric-specific fields and logic.
C. Create a new ElectricVehicle interface and modify all existing vehicle classes to implement it.
D. Add a god-class that handles all electric vehicle and charging spot logic, bypassing existing abstractions.

Solution

  1. Step 1: Identify extensibility without modifying existing classes

    Adding new enum values and subclasses extends functionality without changing existing code, preserving OCP.
  2. Step 2: External update of compatibility map

    Updating the compatibility map externally allows new vehicle and spot types to integrate without altering existing class logic.
  3. Final Answer:

    Option A -> Option A
  4. Quick Check:

    New enums + subclass + external map update -> no existing class modified [check]
Hint: New enums + subclass + external map -> extend without modify [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