SOLID подробно с примерами
↑ 8.1 Парадигмы: ООП, ФП, SOLID · ← Предыдущая · → Следующая
Зачем это на собесе
SOLID спрашивают всегда. Хороший ответ включает примеры из фронтенда и оговорку, что это эвристики.
S — Single Responsibility
У модуля одна причина для изменения.
// плохо: компонент грузит, кэширует, форматирует, рисует
// хорошо:
const useUserApi = () => { /* запросы */ }
const formatUser = (u: User) => `${u.last} ${u.first}`
// компонент только отображаетO — Open/Closed
Открыт для расширения, закрыт для модификации: добавляем поведение без правки существующего кода.
const validators: Record<string, (v: unknown) => string | null> = { required, email }
export const registerValidator = (name: string, fn: Validator) => { validators[name] = fn }Вместо switch по типу, который растёт, — реестр или стратегия.
L — Liskov Substitution
Подтип можно подставить вместо базового без нарушения ожиданий.
Нарушение: ReadOnlyList extends List и add() бросает исключение. Во фронтенде: компонент-обёртка, меняющая смысл v-model или событий базового.
I — Interface Segregation
Много специализированных интерфейсов лучше одного универсального.
// плохо: компоненту нужен только id
function open(user: FullUser) {}
// хорошо
function open(user: Pick<User, 'id'>) {}Компоненту — минимум props; композиция defineProps небольших типов.
D — Dependency Inversion
Модули верхнего уровня зависят от абстракций, а не от деталей.
export interface HttpClient { get<T>(url: string): Promise<T> }
export class UserService {
constructor(private http: HttpClient) {}
load(id: string) { return this.http.get<User>(`/users/${id}`) }
}
// в тесте подставляем фейковый HttpClientВо Vue: provide/inject, параметры composables, Pinia и сервисы с внедрением.
Оговорка senior
SOLID — эвристики для оценки границ и зависимостей, а не обязательная классовая архитектура. Излишнее следование даёт лишние абстракции (YAGNI). Функциональный стиль решает те же задачи иначе: функции высшего порядка вместо стратегий, замыкания вместо DI.
Вопросы с ответами
Как применить SOLID к Vue-компоненту?
Один компонент — одна ответственность (данные, логика и отображение разделены), расширение через slots и props, узкие props, зависимости через composables и inject.
Пример нарушения принципа подстановки Лисков?
Наследник ужесточает предусловия или ломает контракт: например, обёртка над
input, которая не эмититinput-событие, и потребитель базового компонента перестаёт работать.