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 — надстройка над ООП.