Free Interactive Course · Design Patterns

Facade Design Pattern

One simple door in front of a complicated subsystem — so callers stop learning six classes to do one thing.

Structural Patternseasya.k.a. Front door
ShareXLinkedIn
In one sentence

Provide a unified, higher-level interface to a set of interfaces in a subsystem, making the subsystem easier to use without hiding it from anyone who needs the detail.

01

The problem Facade solves

The problem

Placing an order in your shop takes six calls, in a specific order, and everyone who places one has to know all six: reserve the stock, price the basket with tax and the current promotion, take the payment, hand the pick list to the warehouse, send the confirmation email, then record the conversion for analytics.

The web controller does it. So does the mobile API. So does the admin "place this order for the customer" screen, the CSV importer, and two integration tests. Six copies of the same choreography.

Then the rules change: payment now has to happen after the fraud check, and the fraud check is a new seventh service. You have to find all six copies. You will find five, and the CSV importer will quietly keep charging cards before checking for fraud until somebody notices in three weeks.

02

How the Facade pattern works

Write one class whose only job is to know the choreography, and give it a method that reads like the thing you actually wanted to do:

  1. The facade offers a small, task-shaped interface — placeOrder(cart, card), not six primitives in the right order.
  2. It holds the subsystem objects and calls them in the correct sequence, handling the ordering, the roll-back and the plumbing between them.
  3. Callers depend on the facade only. One import instead of six, and the sequence lives in exactly one file.
  4. The subsystem stays public. Anyone with an unusual need can still reach past the facade — it is a convenient door, not a wall.
That last point is the one people get wrong. GoF is explicit that a facade does not forbid access to the subsystem, and a facade that is the only way in stops being a facade and becomes a bottleneck: every unusual requirement has to be added to it, it grows a parameter for each caller's special case, and within a year it is the file everyone edits and nobody understands. Make the common path easy; leave the uncommon path possible.
WebControllerMobileApiCsvImporterOrderFacadeplaceOrder(cart, card)InventoryServicePricingEnginePaymentGatewayWarehouseClientNotifierthree clients, one import each — and the order of the five calls lives in one file
Participants. There are only two: the Facade, which knows the subsystem and the order to call it in, and the subsystem classes, which know nothing about the facade at all. That one-way ignorance matters — the subsystem must stay usable on its own, which is what keeps the facade optional rather than mandatory.
03

See it: one call, five underneath

Place an order through the facade, then remove it and place the same order again. Watch the second counter — the number of classes the caller has to know about — because that number is the whole reason this pattern exists.

▶ Try it — place, cancel, track

An interactive call tracer: CheckoutController calls placeOrder() on the OrderFacade, which fans it out into five ordered calls across InventoryService, PricingEngine, PaymentGateway, WarehouseClient and Notifier. Remove the facade and the controller must make all five itself, in the right order, and depend on all five classes.

Cancelling is the interesting one. Refund then release stock — do it the other way round and a race lets someone buy the item you haven't refunded yet. With the facade, that ordering is decided once, in one file, with a comment explaining why. Without it, it is a piece of folklore living in five controllers.
04

Facade pattern code examples

One task-shaped method; the sequence, the roll-back and the six imports live behind it.

public final class OrderFacade {

    private final InventoryService inventory;
    private final PricingEngine pricing;
    private final PaymentGateway payments;
    private final WarehouseClient warehouse;
    private final Notifier notifier;

    // Constructor omitted — five fields, injected.

    /** The whole point: one method shaped like the thing the caller wanted. */
    public Order placeOrder(Cart cart, Card card) {
        Reservation reservation = inventory.reserve(cart.lines());
        try {
            Quote quote = pricing.quote(cart, cart.customer());
            Receipt receipt = payments.charge(quote.total(), card);

            Order order = Order.of(cart, quote, receipt);
            warehouse.dispatch(order);
            notifier.orderPlaced(order);
            return order;

        } catch (PaymentDeclined | WarehouseUnavailable e) {
            // The compensating action belongs here too. This is exactly the line
            // every hand-rolled copy of the sequence forgets.
            inventory.release(reservation);
            throw e;
        }
    }
}

// The controller shrinks to one line and one import:
//
//     @PostMapping("/orders")
//     Order create(@RequestBody Cart cart, Card card) {
//         return orders.placeOrder(cart, card);
//     }
//
// Note what the facade does NOT do: no pricing rules, no retry policy, no tax
// logic. It sequences, it compensates, it stops. The moment business rules move
// in, you have a god object wearing a pattern's name.
Read across the tabs: Python, JavaScript and Go barely need a class — a module or package with a small exported surface is already a facade, and __all__, a barrel file and unexported types are the language's way of spelling it. C++ gets a benefit the others don't have: putting the subsystem headers behind a pimpl means callers stop recompiling when a subsystem header changes. Java and C# use a class mostly so the five dependencies can be injected and faked in tests.
05

How to implement Facade

  1. Find the sequence that keeps getting copied. The facade's methods should be named after the task (placeOrder), never after the mechanics (reserveAndChargeAndDispatch).
  2. Create one class — or, in Python, Go and JavaScript, one module — that holds the subsystem objects and performs the sequence.
  3. Move the ordering, the roll-back and the glue in. Leave the business rules out: a facade that starts calculating tax has stopped being a facade.
  4. Return your own result type, not a tuple of subsystem objects, so callers still don't need the subsystem's vocabulary.
  5. Keep the subsystem public. If a caller genuinely needs something the facade doesn't offer, they should reach past it rather than force a new parameter into it.
  6. Point the existing callers at the facade and delete their copies of the sequence. If a copy has to stay, find out why — that difference is usually a bug.
06

When to use Facade — and when not to

Use it when a subsystem is genuinely complicated and most callers only ever want the same one or two journeys through it; when the same call sequence is duplicated across several entry points; when you want a layer boundary you can actually enforce; or when you need to keep a big dependency — a legacy module, a vendor SDK, an entire library — reachable from one file instead of two hundred.

Where it goes wrong

The god object. Every new requirement gets one more method, and three years later OrderFacade is four thousand lines with forty dependencies. A facade should stay thin; when it grows, split it by journey rather than adding to it.

The mandatory facade. Making the subsystem package-private so everything must go through the door converts a convenience into a bottleneck, and every edge case becomes a new boolean parameter. Simplify the common path; leave the rest reachable.

The pass-through. A facade whose methods each call exactly one subsystem method, with the same name and arguments, adds an indirection and nothing else. If there is no sequencing, no compensation and no simplification, delete it.

Business logic creep. Ordering and roll-back belong in a facade. Pricing rules, retry policies and tax do not — those belong in the subsystem, where they can be tested without five fakes.

You want to…UseBecause
Give many classes one simple, task-shaped entry pointFacadeA new, smaller interface over a subsystem you chose to simplify.
Make one incompatible class fit an interface you already callAdapterAdapter matches an existing interface; Facade invents a new one.
Keep the interface identical but control access to the objectProxyProxy governs calls; Facade reduces their number.
Add behaviour to one object while keeping its interfaceDecoratorDecorator wraps one object and stacks; Facade fronts many and doesn't.
Let a set of peers coordinate without knowing each otherMediatorA mediator's colleagues talk through it; a facade's subsystem doesn't know it exists.
07

Quick check

🧠 Quick check
A reviewer suggests making all five subsystem classes package-private so that every caller is forced to go through OrderFacade. Good idea?

In the wild

Javajavax.faces.context.FacesContext and the JDBC DriverManager; Spring's JdbcTemplate is a facade over the raw JDBC connection, statement and result-set dance.
Pythonrequests — requests.get(url) is a facade over urllib3's connection pools, retries, encoding and cookie handling. The library's own tagline is essentially the pattern's intent.
C#HttpClient over SocketsHttpHandler, and File.ReadAllText() hiding the stream, reader and encoding detection.
Gohttp.Get() — a package-level facade over DefaultClient, its transport, and the request it builds for you.
JavaScriptfetch() over XHR and the browser's networking stack; and every index.js barrel that curates a package's public surface.
C++std::filesystem::copy_file hides platform APIs, and the pimpl idiom itself is a facade adopted for compile-time isolation.

Frequently asked questions

What is the difference between the Facade and Adapter patterns?
Adapter is forced on you: some class has the wrong interface and your code cannot call it, so you write a translator to a shape that already exists. Facade is chosen by you: everything is perfectly callable, just tedious, so you invent a new and smaller interface over several classes. Rough test — an adapter usually wraps one object and changes its interface; a facade usually wraps several and reduces how many calls you make. Delete an adapter and the code stops compiling; delete a facade and the code still works, just worse.
Is a Facade the same as a service layer?
A service layer is usually implemented as facades, but the two ideas answer different questions. "Service layer" is architectural: it names a tier that sits between your controllers and your domain. "Facade" is a class-level pattern: one simple interface over a complicated set of collaborators. A service class that orchestrates five repositories is a facade; a service class that contains the business rules themselves is a domain service, and calling it a facade is where the god object usually starts.
Should a Facade have an interface?
The pattern doesn't need one — the subsystem has no idea the facade exists, so there is nothing to polymorphise. Add an interface when you have a concrete reason: faking the facade in a controller's tests, or swapping implementations per environment. Adding one reflexively gives you a second file that always changes with the first.
Can a Facade have more than one method?
Yes, and most do — one per task the callers actually perform. The number to watch is not the method count but the dependency count and whether the methods still describe journeys. Three methods over five subsystems is healthy. Forty methods over forty dependencies is a god object that got named after a pattern.
Does a Facade hide the subsystem completely?
No, and it shouldn't. GoF specifically notes that clients who need the subsystem directly can still use it. The facade makes the common path a single call; the unusual caller reaching past it is the pattern working as designed, not a violation. When you truly must prevent direct access — money movement, audit trails — enforce that with a transactional boundary or a permissions model, not by pretending a convenience class is a wall.

Finish the handbook, earn the certificate

All 23 Gang-of-Four patterns, each with a simulator you can click and code in seven languages. Free, no signup.

See all 23 patterns →
Found this course useful? Share it.
ShareXLinkedIn

Comments

0

Join the conversation. Sign in to leave a comment — we'd love to hear your thoughts.