iwantcoding.com
🔥 Daily 👥 Rooms 🏆 Top Log in Sign up

Examples

Design pattern worked examples: Observer, Strategy, Factory, Adapter, Decorator.

Design patterns — examples

EXAMPLE
// ===== 1. Observer (pub/sub) =====
class EventBus {
  private listeners = new Map<string, Function[]>();

  on(event: string, fn: Function) {
    if (!this.listeners.has(event)) this.listeners.set(event, []);
    this.listeners.get(event)!.push(fn);
    return () => this.off(event, fn);  // unsubscribe
  }
  off(event: string, fn: Function) {
    const arr = this.listeners.get(event);
    if (arr) this.listeners.set(event, arr.filter(f => f !== fn));
  }
  emit(event: string, payload: any) {
    for (const fn of this.listeners.get(event) ?? []) fn(payload);
  }
}

const bus = new EventBus();
const off = bus.on('order.placed', (o) => console.log('email:', o.id));
bus.emit('order.placed', { id: 1 });
off();

// ===== 2. Strategy =====
interface Pricer { price(order: Order): number }
class RetailPricer    implements Pricer { price(o: Order) { return o.subtotal; } }
class WholesalePricer implements Pricer { price(o: Order) { return o.subtotal * 0.9; } }
class VipPricer       implements Pricer { price(o: Order) { return o.subtotal * 0.8; } }

function quote(order: Order, pricer: Pricer) {
  return pricer.price(order);
}

// ===== 3. Factory =====
interface Animal { speak(): string }
class Dog implements Animal { speak() { return 'woof'; } }
class Cat implements Animal { speak() { return 'meow'; } }

class AnimalFactory {
  static create(kind: 'dog' | 'cat'): Animal {
    switch (kind) {
      case 'dog': return new Dog();
      case 'cat': return new Cat();
      default: throw new Error('unknown');
    }
  }
}

const pet = AnimalFactory.create('dog');

// ===== 4. Adapter =====
// Old API:
class LegacyLogger {
  log_message(level: string, text: string) { console.log(\`[${level}] ${text}\`); }
}

// New API your code expects:
interface Logger { info(msg: string): void; error(msg: string): void; }

class LegacyLoggerAdapter implements Logger {
  constructor(private legacy: LegacyLogger) {}
  info(msg: string) { this.legacy.log_message('INFO', msg); }
  error(msg: string) { this.legacy.log_message('ERROR', msg); }
}

const logger: Logger = new LegacyLoggerAdapter(new LegacyLogger());
logger.info('hello');

// ===== 5. Decorator =====
interface Coffee { cost(): number }
class SimpleCoffee implements Coffee { cost() { return 5; } }

class MilkDecorator implements Coffee {
  constructor(private inner: Coffee) {}
  cost() { return this.inner.cost() + 1; }
}
class SugarDecorator implements Coffee {
  constructor(private inner: Coffee) {}
  cost() { return this.inner.cost() + 0.5; }
}

const order: Coffee = new SugarDecorator(new MilkDecorator(new SimpleCoffee()));
console.log(order.cost());  // 6.5

// ===== 6. Singleton (carefully) =====
class Settings {
  private static instance: Settings;
  private constructor(public data: Record<string, any> = {}) {}
  static get(): Settings {
    if (!Settings.instance) Settings.instance = new Settings();
    return Settings.instance;
  }
}

// Use sparingly; singletons hide dependencies.

// ===== Patterns =====
// - Observer for cross-component events
// - Strategy for interchangeable algorithms
// - Factory for hidden construction logic
// - Adapter to bridge incompatible interfaces
// - Decorator for stacking behaviour
// - Singleton only when truly global

// ===== Pitfalls =====
// - Over-applying patterns -> ceremony
// - Strategy with one impl -> just inline
// - Adapter that hides bad APIs -> rewrite if you can
// - Decorators stacked deep -> hard to debug
// - Singletons as hidden global state

Why it matters

Worked design patterns: Observer (pub/sub), Strategy (interchangeable algorithms), Factory (hidden construction), Adapter (bridge APIs), Decorator (stack behaviour), Singleton (use sparingly). Master the shapes; resist applying them where simpler code would do.

Tip: Tweak the snippet with Try it Yourself », then sit the quiz at the bottom of the page.

Example

Example
// Each lesson body shows the SHAPE of the pattern with one runnable snippet.
Try it Yourself »

Discussion

Loading…