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:
typescript1// Multiple subsystems to coordinate2const 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();910// Client must coordinate everything11async function createShipment(order: Order) {12 // Validate address13 const validAddress = await addressValidator.validate(order.destination);14 if (!validAddress.isValid) throw new Error('Invalid address');1516 // Geocode for zone calculation17 const coords = await geocoder.geocode(validAddress);1819 // Calculate rates20 const rates = await rateCalculator.calculate(order.weight, coords);2122 // Select best carrier23 const carrier = carrierSelector.selectBest(rates, order.preferences);2425 // Check inventory26 const available = await inventoryService.checkAvailability(order.items);27 if (!available) throw new Error('Items not available');2829 // Generate label30 const label = await labelGenerator.generate(carrier, order);3132 // Send notification33 await notificationService.sendShippingConfirmation(order.customer, label);3435 return label;36}
The Solution: Facade
Create a simplified interface:
typescript1class 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: NotificationService10 ) {}1112 async createShipment(order: Order): Promise<ShipmentResult> {13 // All complexity hidden behind one method14 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);1920 return { label, carrier, estimatedDelivery: carrier.eta };21 }2223 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}2930// Client code is simple31const 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
- Simplification - Complex operations become simple method calls
- Decoupling - Clients don't depend on subsystem classes
- Layering - Creates clear boundaries between layers
- Entry point - Provides a convenient starting point for common tasks
When to Use Facade
- Complex subsystems - Many classes that work together
- Common workflows - Standard sequences of operations
- Legacy systems - Simplify access to old, complex code
- Third-party APIs - Wrap external services
Facade vs Adapter
| Aspect | Facade | Adapter |
|---|---|---|
| Purpose | Simplify interface | Convert interface |
| Scope | Multiple subsystems | Single class |
| Direction | Simplifying | Compatibility |
Summary
Facade is the "easy button" for complex subsystems. It doesn't add functionality - it just makes existing functionality easier to use.