🧠
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