DEV Community

Cover image for Facade: The Hotel Reception Pattern
Vignesh Athiappan
Vignesh Athiappan

Posted on

Facade: The Hotel Reception Pattern

You check into a hotel. You want a room sorted, a taxi booked, dinner reserved, and a wake-up call.

Do you hunt down the housekeeping department, then the transport desk, then the kitchen, then the operator, one at a time? No. You call reception and say "sort all this out." Reception knows who to call behind the scenes. You talk to one person instead of five.

That's the Facade pattern: one simple front door that hides a messy, complicated system behind it.

The problem: the caller has to know everything

Say placing an order actually involves four subsystems, in a specific order:

// Every caller has to know ALL of this, in the RIGHT sequence
var inventory = new InventoryService();
if (!inventory.CheckStock(itemId)) return;
inventory.Reserve(itemId);

var payment = new PaymentService();
payment.Charge(customerId, amount);

var shipping = new ShippingService();
var trackingId = shipping.Schedule(itemId, address);

var notifier = new EmailService();
notifier.Send(customerId, $"Order placed! Track: {trackingId}");
Enter fullscreen mode Exit fullscreen mode

Every place that needs to place an order repeats all of this — every service, every method, the exact sequence. Change the steps once and you're editing it everywhere.

The Facade

Wrap the whole mess behind one class with one simple method:

public class OrderFacade
{
    private readonly InventoryService _inventory = new();
    private readonly PaymentService _payment = new();
    private readonly ShippingService _shipping = new();
    private readonly EmailService _email = new();

    // one simple door
    public void PlaceOrder(int customerId, int itemId, decimal amount, string address)
    {
        if (!_inventory.CheckStock(itemId)) throw new Exception("Out of stock");
        _inventory.Reserve(itemId);
        _payment.Charge(customerId, amount);
        var trackingId = _shipping.Schedule(itemId, address);
        _email.Send(customerId, $"Order placed! Track: {trackingId}");
    }
}
Enter fullscreen mode Exit fullscreen mode

Now the caller's entire job is one line:

var order = new OrderFacade();
order.PlaceOrder(customerId: 1, itemId: 42, amount: 999, address: "Bengaluru");
Enter fullscreen mode Exit fullscreen mode

The caller has no idea there are four services and a specific sequence behind it — exactly like the hotel guest has no idea reception rang four departments.

The key insight

The subsystems still exist and still work as before. The Facade doesn't remove complexity — it hides it behind a clean entry point. And it isn't a wall: if some advanced caller genuinely needs PaymentService directly, it's still there. The Facade is a convenience, not a lockdown.

Facade vs Adapter — both wrap, different purpose

This is the confusion worth clearing up:

  • Adapter wraps one thing to change its shape so it fits somewhere it didn't before. Purpose: compatibility.
  • Facade wraps many things to give one simple entry point. Purpose: simplicity.

Adapter is one object with a different shape. Facade is many objects behind one easy door.

Where you've already seen it

HttpClient is a facade. Behind that one friendly class sits DNS resolution, sockets, TLS handshakes, and connection pooling. You just call GetAsync() and none of that surfaces. Most well-designed "Service" classes in an app are facades too — a clean method on top of repositories, validators, and mappers.

One line to remember

Facade = hotel reception. One simple door in front; it coordinates the messy departments behind the scenes.


Part 6 of a series on must-know design patterns in C#, explained the simple way. Earlier parts covered Singleton, Factory Method, Builder, Adapter, and Decorator. Next up: Proxy — the bodyguard pattern.

Top comments (0)