← Facade lesson
Lab

Facade

type AlterationRequest = { customer: string; garment: string; work: string };
type WorkOrder = { id: string; request: AlterationRequest };
type IntakeResult = { orderId: string; slipPrinted: boolean };

// The subsystem: four services, each with one job.
class Validator {
  check(request: AlterationRequest): void {
    const { customer, garment, work } = request;
    if (!customer || !garment || !work) throw new Error('incomplete request');
  }
}
class Queue {
  private next = 1;
  reserve(): string {
    return `ALT-${this.next++}`;
  }
}
class OrderBook {
  orders: WorkOrder[] = [];
  record(order: WorkOrder): void {
    this.orders.push(order);
  }
}
class Printer {
  jammed = true; // the first slip jams; the next ones print
  print(order: WorkOrder): void {
    if (this.jammed) {
      this.jammed = false;
      throw new Error(`printer jammed on ${order.request.customer}'s slip`);
    }
  }
}

// The facade: one operation for the whole intake.
class IntakeDesk {
  constructor(
    private validator: Validator,
    private queue: Queue,
    private book: OrderBook,
    private printer: Printer,
  ) {}

  acceptAlteration(request: AlterationRequest): IntakeResult {
    this.validator.check(request);
    const order = { id: this.queue.reserve(), request };
    this.book.record(order);
    try {
      this.printer.print(order);
      return { orderId: order.id, slipPrinted: true };
    } catch {
      return { orderId: order.id, slipPrinted: false };
    }
  }
}

const book = new OrderBook();
const desk = new IntakeDesk(new Validator(), new Queue(), book, new Printer());

// Each caller makes one call and tells its customer what happened.
function take(caller: string, request: AlterationRequest): void {
  try {
    const result = desk.acceptAlteration(request);
    const slip = result.slipPrinted ? 'slip printed' : 'no slip';
    console.log(`${caller}: accepted ${result.orderId}, ${slip}`);
  } catch (error) {
    console.log(`${caller}: not accepted (${(error as Error).message})`);
  }
}

take('counter', { customer: 'Mina', garment: 'blue coat', work: 'reline' });
take('phone', { customer: 'Omar', garment: 'grey suit', work: '' });
take('partner', { customer: 'Lena', garment: 'linen dress', work: 'hem' });
const recorded = book.orders.length;
console.log(`work orders recorded: ${recorded}`);