Java > Design Patterns in Java > Structural Patterns > Facade Pattern

Facade Pattern Example: Order Processing System

This code demonstrates the Facade pattern in Java. The Facade pattern provides a simplified interface to a complex subsystem. In this example, we simulate an order processing system, where multiple components (Inventory, Payment, Shipping) are involved. The OrderFacade simplifies the process of placing an order by hiding the complexities of these underlying components.

OrderFacade Class

The OrderFacade class acts as a facade. It encapsulates the complex interaction between the Inventory, Payment, and Shipping subsystems. The placeOrder method provides a simplified interface for placing an order. The client only interacts with the facade, not the individual subsystems directly.

public class OrderFacade {
    private Inventory inventory;
    private Payment payment;
    private Shipping shipping;

    public OrderFacade() {
        this.inventory = new Inventory();
        this.payment = new Payment();
        this.shipping = new Shipping();
    }

    public void placeOrder(String productId, int quantity, String paymentDetails, String shippingAddress) {
        if (inventory.checkAvailability(productId, quantity)) {
            if (payment.processPayment(paymentDetails)) {
                shipping.shipProduct(productId, quantity, shippingAddress);
                System.out.println("Order placed successfully!");
            } else {
                System.out.println("Payment failed. Order not placed.");
            }
        } else {
            System.out.println("Product out of stock. Order not placed.");
        }
    }
}

Inventory Subsystem

The Inventory class represents one of the subsystems. It handles checking the availability of products. In a real-world scenario, this class would interact with a database or other inventory management system.

class Inventory {
    public boolean checkAvailability(String productId, int quantity) {
        // Simulate checking inventory
        System.out.println("Checking inventory for product " + productId + ", quantity: " + quantity);
        return quantity <= 10; // Simulate limited stock
    }
}

Payment Subsystem

The Payment class represents the payment subsystem. It handles processing payments. In a real-world scenario, this class would interact with a payment gateway.

class Payment {
    public boolean processPayment(String paymentDetails) {
        // Simulate processing payment
        System.out.println("Processing payment with details: " + paymentDetails);
        return true; // Simulate successful payment
    }
}

Shipping Subsystem

The Shipping class represents the shipping subsystem. It handles shipping products. In a real-world scenario, this class would interact with a shipping provider.

class Shipping {
    public void shipProduct(String productId, int quantity, String shippingAddress) {
        // Simulate shipping product
        System.out.println("Shipping product " + productId + ", quantity: " + quantity + " to address: " + shippingAddress);
    }
}

Client Code

The Main class demonstrates how to use the OrderFacade. The client code only needs to interact with the facade, simplifying the order placement process.

public class Main {
    public static void main(String[] args) {
        OrderFacade orderFacade = new OrderFacade();
        orderFacade.placeOrder("Product123", 5, "Credit Card", "123 Main St");
    }
}

Concepts Behind the Snippet

The Facade pattern aims to reduce the complexity of interacting with a complex system. It provides a higher-level interface that makes the subsystem easier to use. The key concept is encapsulation of complex interactions behind a simpler interface.

Real-Life Use Case

A common real-life use case is a compiler. A compiler takes source code as input and transforms it into executable code. This process involves multiple phases like lexical analysis, parsing, semantic analysis, code generation, and optimization. A facade can provide a simple compile() method that orchestrates all these phases, hiding the complexity from the user.

Best Practices

  • The Facade should not expose the underlying subsystems directly.
  • The Facade should focus on providing a simplified interface for common use cases.
  • Avoid creating a 'God' Facade that tries to do everything. It should be focused on a specific task.

When to Use Them

Use the Facade pattern when:

  • You want to provide a simple interface to a complex subsystem.
  • You want to reduce the dependencies between clients and the subsystem.
  • You want to layer your system.

Pros

  • Simplifies the interface for clients.
  • Reduces dependencies between clients and subsystems.
  • Promotes loose coupling.

Cons

  • Can become a God object if not carefully designed.
  • May not provide enough flexibility for all use cases.

FAQ

  • What is the difference between Facade and Adapter pattern?

    The Facade pattern provides a simplified interface to a complex subsystem, hiding the complexity from the client. The Adapter pattern, on the other hand, allows incompatible interfaces to work together. It converts the interface of a class into another interface clients expect.

  • Is the Facade pattern similar to an API?

    Yes, the Facade pattern can be seen as a simplified API for a subsystem. It provides a well-defined entry point for clients to interact with the complex underlying components.