You’re building an e-commerce checkout system. It needs to validate inventory, process payment, update stock, send confirmation emails, and create shipping labels. Your client code would need to know about inventory services, payment gateways, email services, and shipping APIs. The Facade pattern provides a simple interface that hides this complexity, making your code cleaner and easier to use.
Problem
Consider a home theater system with multiple components:
public class Amplifier
{
public void On() => Console.WriteLine("Amplifier on");
public void SetVolume(int level) => Console.WriteLine($"Volume set to {level}");
public void Off() => Console.WriteLine("Amplifier off");
}
public class DvdPlayer
{
public void On() => Console.WriteLine("DVD Player on");
public void Play(string movie) => Console.WriteLine($"Playing {movie}");
public void Off() => Console.WriteLine("DVD Player off");
}
public class Projector
{
public void On() => Console.WriteLine("Projector on");
public void WideScreenMode() => Console.WriteLine("Widescreen mode");
public void Off() => Console.WriteLine("Projector off");
}
public class Lights
{
public void Dim(int level) => Console.WriteLine($"Lights dimmed to {level}%");
public void On() => Console.WriteLine("Lights on");
}
To watch a movie, you’d need to:
var amp = new Amplifier();
var dvd = new DvdPlayer();
var projector = new Projector();
var lights = new Lights();
amp.On();
amp.SetVolume(5);
dvd.On();
dvd.Play("Inception");
projector.On();
projector.WideScreenMode();
lights.Dim(10);
This is too complex. Clients shouldn’t need to know about all these subsystems and their interactions.
Solution
The Facade pattern provides a simplified interface to a complex subsystem. It defines a higher-level interface that makes the subsystem easier to use.
Definition: The Facade pattern provides a simplified interface to a library, a framework, or any other complex set of classes.
A facade doesn’t hide subsystem functionality—it provides a convenient entry point. Clients can still access subsystem classes directly if needed, but the facade offers a simpler way for common tasks.
Pseudocode
Client
↓ uses
Facade (HomeTheaterFacade)
↓ coordinates
Subsystem Classes (Amplifier, DvdPlayer, Projector, Lights)
Examples
Here’s a complete, runnable C# implementation:
using System;
// Subsystem classes
public class Amplifier
{
public void On() => Console.WriteLine("Amplifier on");
public void SetVolume(int level) => Console.WriteLine($"Volume set to {level}");
public void Off() => Console.WriteLine("Amplifier off");
}
public class DvdPlayer
{
public void On() => Console.WriteLine("DVD Player on");
public void Play(string movie) => Console.WriteLine($"Playing {movie}");
public void Stop() => Console.WriteLine("DVD Player stopped");
public void Off() => Console.WriteLine("DVD Player off");
}
public class Projector
{
public void On() => Console.WriteLine("Projector on");
public void WideScreenMode() => Console.WriteLine("Widescreen mode enabled");
public void Off() => Console.WriteLine("Projector off");
}
public class Lights
{
public void Dim(int level) => Console.WriteLine($"Lights dimmed to {level}%");
public void On() => Console.WriteLine("Lights on");
}
// Facade
public class HomeTheaterFacade
{
private Amplifier _amp;
private DvdPlayer _dvd;
private Projector _projector;
private Lights _lights;
public HomeTheaterFacade(Amplifier amp, DvdPlayer dvd, Projector projector, Lights lights)
{
_amp = amp;
_dvd = dvd;
_projector = projector;
_lights = lights;
}
public void WatchMovie(string movie)
{
Console.WriteLine("Get ready to watch a movie...");
_lights.Dim(10);
_projector.On();
_projector.WideScreenMode();
_amp.On();
_amp.SetVolume(5);
_dvd.On();
_dvd.Play(movie);
}
public void EndMovie()
{
Console.WriteLine("Shutting movie theater down...");
_dvd.Stop();
_dvd.Off();
_amp.Off();
_projector.Off();
_lights.On();
}
}
// Usage
class Program
{
static void Main()
{
// Create subsystem components
var amp = new Amplifier();
var dvd = new DvdPlayer();
var projector = new Projector();
var lights = new Lights();
// Create facade
var homeTheater = new HomeTheaterFacade(amp, dvd, projector, lights);
// Simple interface
homeTheater.WatchMovie("Inception");
Console.WriteLine();
homeTheater.EndMovie();
}
}
Output:
Get ready to watch a movie...
Lights dimmed to 10%
Projector on
Widescreen mode enabled
Amplifier on
Volume set to 5
DVD Player on
Playing Inception
Shutting movie theater down...
DVD Player stopped
DVD Player off
Amplifier off
Projector off
Lights on
Real-World Example: E-Commerce Checkout
// Subsystem classes
public class InventoryService
{
public bool CheckAvailability(string productId, int quantity)
{
Console.WriteLine($"Checking availability for {productId} (qty: {quantity})");
return true; // Simplified
}
public void UpdateStock(string productId, int quantity)
{
Console.WriteLine($"Updating stock for {productId}: -{quantity}");
}
}
public class PaymentService
{
public bool ProcessPayment(decimal amount, string cardNumber)
{
Console.WriteLine($"Processing payment of ${amount}");
return true; // Simplified
}
}
public class ShippingService
{
public string CreateShippingLabel(string address)
{
Console.WriteLine($"Creating shipping label for {address}");
return "SHIP-12345";
}
}
public class EmailService
{
public void SendConfirmation(string email, string orderId)
{
Console.WriteLine($"Sending confirmation email to {email} for order {orderId}");
}
}
// Facade
public class CheckoutFacade
{
private InventoryService _inventory;
private PaymentService _payment;
private ShippingService _shipping;
private EmailService _email;
public CheckoutFacade(
InventoryService inventory,
PaymentService payment,
ShippingService shipping,
EmailService email)
{
_inventory = inventory;
_payment = payment;
_shipping = shipping;
_email = email;
}
public bool ProcessOrder(string productId, int quantity, decimal amount,
string cardNumber, string address, string email)
{
Console.WriteLine("Starting checkout process...\n");
// Validate inventory
if (!_inventory.CheckAvailability(productId, quantity))
{
Console.WriteLine("Product not available");
return false;
}
// Process payment
if (!_payment.ProcessPayment(amount, cardNumber))
{
Console.WriteLine("Payment failed");
return false;
}
// Update inventory
_inventory.UpdateStock(productId, quantity);
// Create shipping label
var shippingLabel = _shipping.CreateShippingLabel(address);
// Send confirmation
_email.SendConfirmation(email, shippingLabel);
Console.WriteLine("\nCheckout completed successfully!");
return true;
}
}
// Usage
var checkout = new CheckoutFacade(
new InventoryService(),
new PaymentService(),
new ShippingService(),
new EmailService()
);
checkout.ProcessOrder(
productId: "PROD-123",
quantity: 2,
amount: 99.99m,
cardNumber: "1234-5678-9012-3456",
address: "123 Main St",
email: "customer@example.com"
);
Applications
Enterprise Use Cases:
- API Wrappers: Simplifying complex third-party APIs (payment gateways, cloud services)
- Framework Integration: Providing simple interfaces to complex frameworks
- Legacy System Integration: Creating modern interfaces for legacy systems
- Microservices Orchestration: Coordinating multiple microservices through a single facade
- Database Access: Simplifying complex database operations
- File System Operations: Providing simple interfaces for complex file operations
- Configuration Management: Simplifying access to complex configuration systems
- Logging Frameworks: Providing simple logging interfaces that hide complexity
Benefits:
- Simplifies client code by hiding subsystem complexity
- Reduces coupling between clients and subsystems
- Makes subsystems easier to use
- Provides a single entry point for common operations
- Doesn’t prevent direct access to subsystems when needed
When to Use:
- You want to provide a simple interface to a complex subsystem
- You want to layer your subsystems—use facades to define entry points
- You want to decouple clients from subsystem components
- You need to wrap a poorly designed API with a better interface
Key Insight: A facade doesn’t add functionality—it simplifies access. It coordinates multiple subsystem classes to perform common tasks, making complex operations appear simple to clients.
