Bird
Raised Fist0
Interview Prepoop-design-patternsmediumAmazonGoogleMicrosoftFlipkartRazorpayZepto

Adapter vs Facade vs Proxy - Structural Pattern Comparison

Choose your preparation mode3 modes available

Start learning this pattern below

Jump into concepts and practice - no test required

or
Recommended
Test this pattern10 questions across easy, medium, and hard to know if this pattern is strong
🎯
Adapter vs Facade vs Proxy - Structural Pattern Comparison
mediumOOPAmazonGoogleMicrosoft

Imagine you have a legacy payment system that speaks a different language than your new app, a complex home automation system you want to simplify for users, and a security guard controlling access to a sensitive resource. How do you design these interactions cleanly?

💡 Beginners often confuse these patterns because they all deal with object composition and interfaces, but their intents and use cases differ significantly. Adapter focuses on making incompatible interfaces work together, Facade simplifies complex systems by providing a unified interface, and Proxy controls access or adds responsibilities without changing the original object. Understanding these distinctions helps avoid mixing their responsibilities.
📋
Interview Question

Explain the differences and purposes of the Adapter, Facade, and Proxy design patterns. When and why would you use each? Compare their roles in structural design patterns.

Intent and purpose of Adapter, Facade, and Proxy patternsHow each pattern changes or controls access to underlying componentsUse cases and trade-offs for each pattern
💡
Scenario & Trace
ScenarioIntegrating a new payment gateway with an existing e-commerce platform that expects a different interface
The Adapter wraps the new payment gateway's interface and translates calls into the format expected by the platform, enabling compatibility without changing existing code.
ScenarioProviding a simplified interface to a complex home automation system with many subsystems like lighting, HVAC, and security
The Facade exposes a single unified interface that internally coordinates calls to multiple subsystems, hiding complexity from the client.
ScenarioControlling access to a sensitive database by adding authentication and caching layers without changing the database code
The Proxy acts as a surrogate that intercepts client requests, performs access control and caching, then forwards requests to the real database object.
  • What if the Adapter needs to support multiple incompatible interfaces simultaneously?
  • How does the Facade pattern handle subsystem changes or extensions without breaking clients?
  • What happens if the Proxy introduces latency or failure points in critical resource access?
⚠️
Common Mistakes
Confusing Adapter with Facade as both simplify interfaces

Interviewer doubts your grasp of pattern intent and design goals

Remember Adapter changes interface to make incompatible interfaces work together; Facade simplifies a complex subsystem with a unified interface.

Thinking Proxy always adds security or caching

Interviewer sees a narrow understanding of Proxy's broader role

Understand Proxy can add various responsibilities like lazy loading, logging, or remote access control, not just security.

Assuming Facade changes subsystem interfaces

Interviewer questions your understanding of subsystem encapsulation

Facades do not alter subsystem interfaces; they provide a new simplified interface on top.

Believing Adapter and Proxy both wrap incompatible interfaces

Interviewer suspects confusion between compatibility and access control

Adapter wraps to translate interfaces; Proxy wraps to control or enhance access to the same interface.

🧠
Basic Definition - What It Is
💡 This level covers the essential purpose and difference of each pattern in simple terms, helping beginners grasp their core intent and avoid confusion.

Intuition

Adapter makes incompatible interfaces compatible, Facade simplifies complex systems, Proxy controls access to an object.

Explanation

The Adapter pattern allows two incompatible interfaces to work together by wrapping one interface with another. The Facade pattern provides a simplified interface to a complex subsystem, hiding its internal complexity. The Proxy pattern acts as a placeholder or surrogate for another object to control access, add functionality like lazy loading or security, without changing the original object's code.

Memory Hook

💡 Adapter = Translator, Facade = Simplifier, Proxy = Gatekeeper

Illustrative Code

class OldPaymentSystem:
    def pay(self, amount):
        print(f"Paying {amount} using old system")

class NewPaymentGateway:
    def make_payment(self, value):
        print(f"Making payment of {value} via new gateway")

class PaymentAdapter:
    def __init__(self, new_gateway):
        self.new_gateway = new_gateway

    def pay(self, amount):
        # Translate pay to make_payment
        self.new_gateway.make_payment(amount)

# Usage
old_system = OldPaymentSystem()
new_gateway = NewPaymentGateway()
adapter = PaymentAdapter(new_gateway)
adapter.pay(100)

Interview Questions

What is the main intent of the Adapter pattern?
  • To convert one interface to another expected by the client
  • To enable compatibility between otherwise incompatible interfaces
How does a Facade help clients?
  • By providing a simple unified interface
  • By hiding the complexity of multiple subsystems
Depth Level
Interview Time30 seconds
Depthbasic

This level focuses on conceptual understanding without code complexity. The Adapter pattern typically adds a constant overhead of method call translation, Facade simplifies client interaction without changing subsystem complexity, and Proxy adds control layers with minimal overhead.

Interview Target: Minimum floor - never go below this

Knowing only this helps pass initial rounds but lacks depth for on-site interviews.

🧠
Mechanism Depth - How It Works
💡 This level explains internal workings, interactions, and typical use cases expected in product company interviews, helping candidates demonstrate deeper understanding.

Intuition

Adapter wraps and translates interfaces, Facade delegates to multiple subsystems, Proxy intercepts and controls requests.

Explanation

The Adapter pattern involves creating a wrapper class that implements the target interface and holds an instance of the incompatible class. It translates client calls into calls understood by the wrapped object. The Facade pattern defines a higher-level interface that delegates client requests to appropriate subsystem classes, coordinating their interactions and hiding their complexity. The Proxy pattern implements the same interface as the real object and controls access by adding pre-processing (e.g., authentication), post-processing, caching, or lazy initialization before forwarding calls to the real object. Each pattern uses composition but with different intents: Adapter focuses on interface compatibility, Facade on simplifying usage, and Proxy on controlling access or adding responsibilities.

Memory Hook

💡 Adapter = Wrapper Translator, Facade = Unified Controller, Proxy = Access Controller

Illustrative Code

class PaymentGateway:
    def make_payment(self, amount):
        print(f"Processing payment of {amount}")

class PaymentAdapter:
    def __init__(self, gateway):
        self.gateway = gateway

    def pay(self, amount):
        # Translate pay to make_payment
        self.gateway.make_payment(amount)

class LightingSystem:
    def turn_on(self):
        print("Lights on")
    def turn_off(self):
        print("Lights off")

class SecuritySystem:
    def arm(self):
        print("Security armed")
    def disarm(self):
        print("Security disarmed")

class HomeFacade:
    def __init__(self, lighting, security):
        self.lighting = lighting
        self.security = security

    def leave_home(self):
        self.lighting.turn_off()
        self.security.arm()

    def arrive_home(self):
        self.security.disarm()
        self.lighting.turn_on()

class Database:
    def query(self):
        print("Querying database")

class DatabaseProxy:
    def __init__(self, db):
        self.db = db
        self.authenticated = False

    def authenticate(self, user):
        if user == "admin":
            self.authenticated = True
            print("User authenticated")
        else:
            print("Authentication failed")

    def query(self):
        if self.authenticated:
            print("Proxy: Access granted")
            self.db.query()
        else:
            print("Proxy: Access denied")

# Usage
# Adapter
gateway = PaymentGateway()
adapter = PaymentAdapter(gateway)
adapter.pay(200)

# Facade
lighting = LightingSystem()
security = SecuritySystem()
home = HomeFacade(lighting, security)
home.leave_home()
home.arrive_home()

# Proxy
db = Database()
proxy = DatabaseProxy(db)
proxy.query()
proxy.authenticate("admin")
proxy.query()

Interview Questions

How does the Proxy pattern add functionality without changing the real object?
  • By implementing the same interface as the real object
  • By intercepting calls and adding behavior before/after forwarding
  • By controlling access, caching, or lazy loading
What happens if the Facade needs to expose new subsystem features?
  • Facade interface may need extension
  • Clients remain decoupled from subsystem changes
  • Subsystems can evolve independently
Can Adapter be used to support multiple incompatible interfaces?
  • Yes, by implementing multiple adapter classes or interfaces
  • Or by using multiple adapters chained or combined
Depth Level
Interview Time2-3 minutes
Depthintermediate

Adapter adds a constant time overhead for translating calls. Facade simplifies client interaction but underlying subsystem complexity remains unchanged. Proxy adds overhead for access control or caching, which can vary but typically is O(1) per call. Space overhead is minimal for all, mainly storing references to wrapped objects.

Interview Target: Target level for FAANG on-sites

Mastering this level distinguishes you from most candidates.

📊
Explanation Depth Levels
💡 Choose your depth based on interview stage and role expectations; deeper knowledge is required for senior or FAANG roles.
LevelInterview TimeSuitable ForRisk
Basic Definition30sScreening call or initial HR roundToo shallow for technical on-site interviews
Mechanism Depth2-3 minutesTechnical interviews at product companies and FAANGInsufficient if you cannot discuss trade-offs or edge cases
💼
Interview Strategy
💡 Use this guide to structure your explanation clearly and confidently before every mock or real interview.

How to Present

Start with a concise definition of each pattern and their intentGive a relatable real-world example or analogy for eachExplain the internal mechanism and how they differ in structure and purposeDiscuss edge cases or trade-offs to show deeper understanding

Time Allocation

Definition: 30s → Example: 1min → Mechanism: 2min → Edge cases: 30s. Total ~4min

What the Interviewer Tests

Your ability to distinguish similar patterns, explain their use cases, and reason about design trade-offs.

Common Follow-ups

  • How would you implement a Proxy that adds caching?
  • Can you combine Adapter and Facade in a system? How?
💡 These follow-ups test your practical understanding and ability to apply patterns in real scenarios.
🔍
Pattern Recognition

When to Use

Interviewers ask about these patterns when discussing system design, code refactoring, or when you mention structural design patterns.

Signature Phrases

'Explain the difference between Adapter, Facade, and Proxy''Compare Adapter and Proxy patterns''What happens when you need to integrate incompatible interfaces?'

NOT This Pattern When

Similar Problems

Practice

(1/5)
1. When a vehicle arrives at the parking lot entrance, trace the sequence of interactions among components to allocate a parking spot and update the system state.
easy
A. Vehicle requests spot allocation from ParkingLot, which uses AllocationStrategy to find a spot, then ParkingSpot is marked occupied
B. ParkingSpot directly checks if it can fit the vehicle and marks itself occupied without consulting ParkingLot
C. Vehicle marks a ParkingSpot as occupied and informs ParkingLot afterward
D. ParkingLot assigns a spot randomly without checking vehicle type or spot availability

Solution

  1. Step 1: Identify correct flow

    The Vehicle initiates the request but does not allocate itself. ParkingLot coordinates allocation using a strategy component to find a suitable spot.
  2. Step 2: Update state

    Once a spot is found, ParkingSpot is marked occupied, and ParkingLot updates its records.
  3. Final Answer:

    Option A -> Option A
  4. Quick Check:

    Centralized coordination and proper state updates ensure consistency [OK]
Hint: Allocation is coordinated by ParkingLot using strategy, not by Vehicle or ParkingSpot alone [OK]
Common Mistakes:
  • Assuming ParkingSpot can allocate itself
  • Vehicle directly marking spots occupied
  • Random assignment ignoring constraints
2. You are designing a system where multiple components need to be notified when certain events occur, but each component only wants to receive notifications for specific event types. Which design approach best ensures loose coupling and efficient event delivery to interested components only?
easy
A. Using a publish-subscribe pattern where components subscribe to event types and get notified only for those
B. Implementing a centralized event queue that all components read from regardless of event type
C. Polling each component periodically to check for event changes
D. Using a brute force approach where the subject notifies all components for every event

Solution

  1. Step 1: Understand the problem constraints

    The system requires notifying multiple components selectively based on event types, ensuring loose coupling.
  2. Step 2: Identify the design pattern that supports selective notification

    The publish-subscribe pattern allows components to subscribe to specific event types and receive notifications only for those, avoiding unnecessary updates and tight coupling.
  3. Final Answer:

    Option A -> Option A
  4. Quick Check:

    Publish-subscribe enables selective, decoupled notifications [OK]
Hint: Selective notification requires publish-subscribe pattern [OK]
Common Mistakes:
  • Assuming polling is efficient for event-driven updates
3. You are designing a system that manages user accounts and sends notification emails. According to the Single Responsibility Principle, how should you organize these responsibilities?
easy
A. Separate user account management and email notification into different classes because each has a different reason to change.
B. Combine user account management and email notification in one class because they are related to users.
C. Put all user-related functionalities, including notifications, into a single class to reduce the number of classes.
D. Create one class for user management and embed email notification logic inside its methods to simplify interactions.

Solution

  1. Step 1: Identify reasons to change

    User account management changes when user data or authentication changes; email notifications change when messaging or delivery requirements change.
  2. Step 2: Apply SRP

    Since these reasons to change differ, they should be separated into different classes to avoid coupling unrelated changes.
  3. Step 3: Evaluate other options

    Options A, C, and D combine responsibilities, increasing coupling and reducing cohesion, violating SRP.
  4. Final Answer:

    Option A -> Option A
  5. Quick Check:

    Separate classes for distinct reasons to change -> SRP compliant.
Hint: One class, one reason to change.
Common Mistakes:
  • Assuming related domain means same responsibility.
  • Combining functionalities to reduce class count.
  • Embedding multiple responsibilities for convenience.
4. What is the time complexity of computing the cost() method when stacking k decorators on a core object using the Decorator Pattern with dynamic behavior injection?
medium
A. O(1) because each decorator adds a fixed cost
B. O(k) because each decorator delegates the call to the next one
C. O(k^2) because each decorator calls all previous decorators recursively
D. O(log k) because decorators form a balanced tree structure

Solution

  1. Step 1: Identify call chain length

    Each decorator's cost() calls the wrapped object's cost(), forming a chain of length k.
  2. Step 2: Calculate total calls

    Cost computation requires traversing all k decorators once, so time complexity is O(k).
  3. Final Answer:

    Option B -> Option B
  4. Quick Check:

    Each decorator adds constant work, total linear in k [OK]
Hint: Decorator calls chain length equals number of decorators [OK]
Common Mistakes:
  • Assuming O(1) because cost is a simple addition
  • Mistaking recursive calls as quadratic
5. What is a key trade-off or limitation when using multiple inheritance to solve the Diamond Problem in object-oriented design?
medium
A. Multiple inheritance always leads to ambiguous method calls that cannot be resolved.
B. Multiple inheritance eliminates the need for Method Resolution Order (MRO).
C. Multiple inheritance reduces code reuse compared to single inheritance.
D. Using multiple inheritance can increase complexity and make the class hierarchy harder to understand and maintain.

Solution

  1. Step 1: Understand the Diamond Problem

    Diamond Problem arises when a class inherits from two classes that share a common ancestor, causing ambiguity.
  2. Step 2: Evaluate Multiple inheritance always leads to ambiguous method calls that cannot be resolved.

    Multiple inheritance can cause ambiguity, but languages use MRO to resolve it, so it is not always unresolved.
  3. Step 3: Evaluate Multiple inheritance eliminates the need for Method Resolution Order (MRO).

    MRO is essential in multiple inheritance to resolve method calls, so multiple inheritance does not eliminate MRO.
  4. Step 4: Evaluate Multiple inheritance reduces code reuse compared to single inheritance.

    Multiple inheritance generally increases code reuse by combining features from multiple classes.
  5. Step 5: Correct trade-off

    Using multiple inheritance can increase complexity and make the class hierarchy harder to understand and maintain. correctly identifies that multiple inheritance increases complexity and can make hierarchies harder to maintain.
  6. Final Answer:

    Option D -> Option D
  7. Quick Check:

    Complexity and maintainability are key trade-offs in multiple inheritance.
Hint: Multiple inheritance = power with complexity cost
Common Mistakes:
  • Believing multiple inheritance always causes irresolvable ambiguity
  • Thinking MRO is unnecessary with multiple inheritance
  • Assuming multiple inheritance reduces code reuse