15 minlesson

Introduction to Facade Pattern

Introduction to Facade Pattern

Facade provides a unified interface to a set of interfaces in a subsystem. It defines a higher-level interface that makes the subsystem easier to use.

The Problem

Complex shipping operations require multiple subsystems:

typescript
1// Multiple subsystems to coordinate
2const addressValidator = new AddressValidator();
3const geocoder = new GeocodingService();
4const rateCalculator = new RateCalculator();
5const carrierSelector = new CarrierSelector();
6const labelGenerator = new LabelGenerator();
7const inventoryService = new InventoryService();
8const notificationService = new NotificationService();
9
10// Client must coordinate everything
11async function createShipment(order: Order) {
12 // Validate address
13 const validAddress = await addressValidator.validate(order.destination);
14 if (!validAddress.isValid) throw new Error('Invalid address');
15
16 // Geocode for zone calculation
17 const coords = await geocoder.geocode(validAddress);
18
19 // Calculate rates
20 const rates = await rateCalculator.calculate(order.weight, coords);
21
22 // Select best carrier
23 const carrier = carrierSelector.selectBest(rates, order.preferences);
24
25 // Check inventory
26 const available = await inventoryService.checkAvailability(order.items);
27 if (!available) throw new Error('Items not available');
28
29 // Generate label
30 const label = await labelGenerator.generate(carrier, order);
31
32 // Send notification
33 await notificationService.sendShippingConfirmation(order.customer, label);
34
35 return label;
36}

The Solution: Facade

Create a simplified interface:

typescript
1class ShippingFacade {
2 constructor(
3 private addressValidator: AddressValidator,
4 private geocoder: GeocodingService,
5 private rateCalculator: RateCalculator,
6 private carrierSelector: CarrierSelector,
7 private labelGenerator: LabelGenerator,
8 private inventoryService: InventoryService,
9 private notificationService: NotificationService
10 ) {}
11
12 async createShipment(order: Order): Promise<ShipmentResult> {
13 // All complexity hidden behind one method
14 const address = await this.validateAndGeocode(order.destination);
15 const carrier = await this.selectBestCarrier(order, address);
16 await this.ensureAvailability(order.items);
17 const label = await this.generateLabel(carrier, order);
18 await this.notify(order.customer, label);
19
20 return { label, carrier, estimatedDelivery: carrier.eta };
21 }
22
23 private async validateAndGeocode(address: Address) { /* ... */ }
24 private async selectBestCarrier(order: Order, address: GeoAddress) { /* ... */ }
25 private async ensureAvailability(items: OrderItem[]) { /* ... */ }
26 private async generateLabel(carrier: Carrier, order: Order) { /* ... */ }
27 private async notify(customer: Customer, label: Label) { /* ... */ }
28}
29
30// Client code is simple
31const facade = new ShippingFacade(/* subsystems */);
32const result = await facade.createShipment(order);

Pattern Structure

1┌──────────┐ ┌─────────────────────────────────────┐
2│ Client │─────────►│ Facade │
3└──────────┘ │─────────────────────────────────────│
4 │ + simpleOperation() │
5 └─────────────────────────────────────┘
6
7 ┌──────────────────┼──────────────────┐
8 │ │ │
9 ┌─────▼─────┐ ┌─────▼─────┐ ┌─────▼─────┐
10 │ Subsystem │ │ Subsystem │ │ Subsystem │
11 │ A │ │ B │ │ C │
12 └───────────┘ └───────────┘ └───────────┘

Key Benefits

  1. Simplification - Complex operations become simple method calls
  2. Decoupling - Clients don't depend on subsystem classes
  3. Layering - Creates clear boundaries between layers
  4. Entry point - Provides a convenient starting point for common tasks

When to Use Facade

  1. Complex subsystems - Many classes that work together
  2. Common workflows - Standard sequences of operations
  3. Legacy systems - Simplify access to old, complex code
  4. Third-party APIs - Wrap external services

Facade vs Adapter

AspectFacadeAdapter
PurposeSimplify interfaceConvert interface
ScopeMultiple subsystemsSingle class
DirectionSimplifyingCompatibility

Summary

Facade is the "easy button" for complex subsystems. It doesn't add functionality - it just makes existing functionality easier to use.