Polymorphism · Indirection · Protected Variations

Три принципа GRASP, отвечающие за устойчивость к изменениям через абстракции.

Polymorphism — поведение через тип

Заменить ветвление по типу на единый интерфейс с разными реализациями.

// плохо
if (shape.type === 'circle') area = π * r²;
else if (shape.type === 'square') area = a*a;

// хорошо: полиморфизм
class Circle { area { return Math.PI * this.r ** 2; } }
class Square { area { return this.a ** 2; } }
shapes.forEach(s => s.area);

Indirection — посредник между связанными

Развязывает A и B через C — Mediator, Observer, Controller.

// EventBus как indirection — отправитель не знает о получателях
bus.on('user.registered', notify);
bus.on('user.registered', logger);
bus.emit('user.registered', user); // отправитель не зацеплен

Protected Variations — защита через стабильные интерфейсы

Точки потенциальных изменений изолированы за интерфейсом — детали меняются, контракт остаётся.

interface Cache {
  get(key: string): Promise<unknown>;
  set(key: string, val: unknown): Promise<void>;
}
// Сегодня Redis, завтра Memcached, послезавтра in-memory — UserService не меняется.
class UserService { constructor(private cache: Cache) {} }

Признаки нарушения

  • Куча if/switch по типу/состоянию вместо полиморфизма.
  • Прямая связь между модулями, которые могли бы общаться через Bus/Mediator.
  • Доменный код напрямую зависит от Postgres, AWS, Stripe — нет Protected Variations.

Антипаттерн

function processPayment(method, sum) {
  if (method === 'stripe') return stripe.charge(sum);
  if (method === 'paypal') return paypal.create(sum);
  if (method === 'crypto') return crypto.tx(sum);
  // новое API — новое ветвление, нет Protected Variations
}

🎓 Источники

  • 🎓 [GRASP принципы с адаптацией для JS и Node.js] · 2021-02-25 · YouTube
    • GRASP Polymorphism ↔ SOLID. Indirection — это Mediator из GoF. Observer — тоже indirection.
  • 🎓 [Принципы GRASP, часть 2] · 2024-07-30 · YouTube
    • Polymorphism GRASP — надстройка над ООП.

См. также