Structural Design Pattern: Facade

The Facade Design Pattern simplifies complex systems by providing a unified interface. It hides intricate operations behind a clean layer, making code easier to use, maintain, and extend without exposing internal details.

Generated via AI

This article is part of a series exploring design patterns using the Java programming language. The goal of this series is to help readers develop a solid understanding of design patterns while also sharing real-world examples from actual codebases that make use of these patterns.

In this article, we’ll be discussing the Facade pattern.

Symbols for better navigation:

🤔 Hypothetical Scenario/Imagination

⚠️ Warning

👉 Point to note

📝 Common Understanding

Facade Pattern

The Facade pattern is one of the simplest yet most powerful structural design patterns. It provides a unified, simplified interface to a complex subsystem.

🤔 Think of a beehive. From the outside, you only see the entrance, a single point of interaction. You don’t need to know about the intricate internal structure: the honeycomb cells, the queen’s chamber, the brood areas, or how thousands of worker bees coordinate their activities. You simply interact with the hive through its entrance.

That’s exactly what the Facade pattern does for complex systems.

👉 The Facade pattern wraps a complicated subsystem with a simpler interface.

Modern software systems often consist of multiple subsystems, classes, and components working together.

When a client needs to interact with these systems, it shouldn’t need to understand the intricate details of every component.

🤔 Imagine you’re building a home theatre system. You have a DVD player, a projector, an amplifier, speakers, lights, and a screen. To watch a movie, you’d have to:

  • Turn on the projector
  • Set the projector input
  • Turn on the amplifier
  • Set the amplifier input and volume
  • Turn on the DVD player
  • Dim the lights
  • Lower the screen

That’s a lot of steps just to watch a movie! A facade can simplify this into a single watchMovie() method.

📝 Common examples of facades include:

  • APIs that wrap complex third-party libraries
  • Utility classes that simplify database operations
  • Service layers that abstract business logic complexity

Recipe to cook the Facade Pattern for objects

Any complex system of many classes can be simplified using a facade by following these steps.

  1. Create the Facade class: Define a new class that will act as the simplified interface.
  2. Declare private instance variables: For each subsystem class, create a private instance variable in the facade.
  3. Initialize subsystem objects in the constructor: Instantiate all the subsystem objects in the facade’s constructor.
  4. Create public methods: Add public methods in the facade that provide simplified operations by internally calling methods on the subsystem objects.

Let’s say we have two subsystem classes A and B:

Java
class A {
    public void doSomethingA() {
        System.out.println("A: Doing something A");
    }
}

class B {
    public void doSomethingB() {
        System.out.println("B: Doing something B");
    }
}

Now, let’s create a facade to combine the functionality of both class A and B.

Java
class Facade {
    private A a;
    private B b;
    
    public Facade() {
        a = new A();
        b = new B();
    }
    
    public void doOperation() { // complex function
        a.doSomethingA();
        b.doSomethingB();
    }
}

With the facade, the client code becomes beautifully simple.

Java
class Test {
    public static void main(String[] args) {
        Facade facade = new Facade();
        facade.doOperation(); // That's it!
    }
}

So now we have a simple interface that hides all the complexity!

The facade handles all the subsystem instantiation and coordination internally, while the client only needs to call doOperation().

👉 Notice that the facade doesn’t eliminate the complexity; it just organizes it better and hides it from clients who don’t need to see it.

Advanced users can still access classes A and B directly if needed.

Case-Study

Let’s look at a real-world scenario where the Facade pattern shines: a restaurant ordering system.

🤔 When you order food at a restaurant, you don’t interact with the kitchen staff, inventory system, payment processor, and delivery service separately. You simply tell the waiter what you want, and they coordinate everything behind the scenes.

A typical ordering system will have the following components.

Java
// Kitchen: To cook food
class Kitchen {
    public void prepareFood(String dish) {
        System.out.println("Kitchen: Preparing " + dish);
    }
    
    public void cookFood(String dish) {
        System.out.println("Kitchen: Cooking " + dish);
    }
    
    public void plateFood(String dish) {
        System.out.println("Kitchen: Plating " + dish);
    }
}

// Inventory: To check availability of items
class Inventory {
    public boolean checkAvailability(String dish) {
        System.out.println("Inventory: Checking availability of " + dish);
        return true;
    }
    
    public void updateStock(String dish) {
        System.out.println("Inventory: Updating stock for " + dish);
    }
}

// Payment: Processing of payments
class PaymentProcessor {
    public boolean processPayment(String method, double amount) {
        System.out.println("Payment: Processing " + method + " payment of $" + amount);
        return true;
    }
    
    public void generateReceipt(String orderId) {
        System.out.println("Payment: Generating receipt for order " + orderId);
    }
}

// Delivery of Food
class DeliveryService {
    public void assignDeliveryPerson(String orderId) {
        System.out.println("Delivery: Assigning delivery person for order " + orderId);
    }
    
    public void dispatch(String orderId) {
        System.out.println("Delivery: Dispatching order " + orderId);
    }
}

⚠️ Now, let’s use all of these systems/classes without the use of Facade. It will become hectic for the developers to use these components in isolation like this.

Java
class CustomerWithoutFacade {
    public static void main(String[] args) {
        // Developer needs to interact with every subsystem!
        Inventory inventory = new Inventory();
        Kitchen kitchen = new Kitchen();
        PaymentProcessor payment = new PaymentProcessor();
        DeliveryService delivery = new DeliveryService();
        
        String dish = "Pasta";
        
        if (inventory.checkAvailability(dish)) {
            inventory.updateStock(dish);
            kitchen.prepareFood(dish);
            kitchen.cookFood(dish);
            kitchen.plateFood(dish);
            payment.processPayment("Credit Card", 15.99);
            payment.generateReceipt("ORD123");
            delivery.assignDeliveryPerson("ORD123");
            delivery.dispatch("ORD123");
        }
    }
}

Let’s simplify placing an order API with a facade now.

Java
class RestaurantFacade {
    private Kitchen kitchen;
    private Inventory inventory;
    private PaymentProcessor payment;
    private DeliveryService delivery;
    
    public RestaurantFacade() {
        this.kitchen = new Kitchen();
        this.inventory = new Inventory();
        this.payment = new PaymentProcessor();
        this.delivery = new DeliveryService();
    }
    
    // Single simplified method for ordering
    public void placeOrder(String dish, String paymentMethod, double amount, String orderId) {
        System.out.println("\n=== Processing Order ===");
        
        // Check availability
        if (!inventory.checkAvailability(dish)) {
            System.out.println("Sorry, " + dish + " is not available!");
            return;
        }
        
        // Prepare the food
        inventory.updateStock(dish);
        kitchen.prepareFood(dish);
        kitchen.cookFood(dish);
        kitchen.plateFood(dish);
        
        // Process payment
        if (!payment.processPayment(paymentMethod, amount)) {
            System.out.println("Payment failed!");
            return;
        }
        payment.generateReceipt(orderId);
        
        // Arrange delivery
        delivery.assignDeliveryPerson(orderId);
        delivery.dispatch(orderId);
        
        System.out.println("\nOrder " + orderId + " completed successfully!");
        System.out.println("======================\n");
    }
}

Now the API usage is dramatically simplified as follows.

Java
class Customer {
    public static void main(String[] args) {
        RestaurantFacade restaurant = new RestaurantFacade();
        
        // Simple one-line order!
        restaurant.placeOrder("Pasta", "Credit Card", 15.99, "ORD123");
    }
}

Real-World Use Case of Facade

One of the most elegant examples of the Facade pattern in the Java JDK is the java.net.URL class.

The URL class provides a simple interface for working with URLs, but behind the scenes, it coordinates with multiple complex subsystems:

  • Protocol handlers (HTTP, HTTPS, FTP, FILE, JAR)
  • Socket connections
  • Input/output streams
  • Security managers
  • Content handlers

🤔 If you had to work with all these components directly every time you wanted to fetch a web page, it would be extremely complicated.

Instead, URL acts as a facade as follows.

Java
class URLExample {
    public static void main(String[] args) {
        try {
            // Simple facade interface
            URL url = new URL("https://example.com");
            
            // Behind the scenes, URL handles:
            // - Protocol selection (https)
            // - DNS resolution
            // - Socket creation
            // - SSL/TLS handshake
            // - HTTP request formatting
            // - Response parsing
            
            BufferedReader reader = new BufferedReader(
                new InputStreamReader(url.openStream())
            );
            
            String line;
            while ((line = reader.readLine()) != null) {
                System.out.println(line);
            }
            reader.close();
            
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

You can see the code below from the URLDeserializedState internal class of the URL class, which rebuilds the URL string from the state values the classes hold. This method alone is sufficient for all types of protocols and handlers that may require the URL string to be rebuilt.

https://github.com/openjdk/jdk/blob/680414d0f9ab75d888bcb284cc494124a01a388f/src/java.base/share/classes/java/net/URL.java#L1816

Up Next in the Series

Proxy Design Pattern

Subscribe to my newsletter today!

Share it on

Leave a Reply

Your email address will not be published. Required fields are marked *