Irbisa · Шпаргалка
ООП, SOLID и паттерны проектирования
Классы и ООП в TypeScript, SOLID, DRY, KISS и YAGNI, связность и зацепление, паттерны GoF во фронтенде: observer, module, factory, strategy, adapter, facade, proxy, антипаттерны
Какие четыре принципа ООП существуют и как каждый из них выглядит в TypeScript?
// abstraction: callers see what a payment method does, not howinterface PaymentMethod { pay(amountCents: number): Promise<string>;} // inheritance: keeps message and stack trace, adds a status code…Чем
privateотличается от#privateв классе TypeScript и что добавляютprotectedиreadonly?class Account { private pin = '1234'; // checked by tsc only, a normal property at runtime #token = 'secret'; // a JavaScript private field, enforced by the engine protected readonly owner: string; constructor(owner: string) {…Когда в TypeScript использовать абстрактный класс, а когда интерфейс?
// the contract callers depend oninterface Uploader { upload(file: Blob): Promise<string>;} // shared algorithm; subclasses fill in the steps marked abstract…Что означают DRY, KISS и YAGNI и когда устранение дублирования делает фронтенд-код хуже?
Что означают слабая связанность (low coupling) и сильная связность (high cohesion) во фронтенд-коде и как распознать код, где нет ни того, ни другого?
Почему в коде на TypeScript композицию обычно предпочитают наследованию и когда наследоваться от класса всё же правильно?
class TagList { protected items: string[] = []; add(tag: string) { this.items.push(tag); } addAll(tags: string[]) {…Что говорят пять принципов SOLID и как каждый выглядит в обычном TypeScript: в сервисах, API-клиентах и валидаторах?
// O: each rule is a value; a new rule is a new function, not another `if` in validate()type Rule = (value: string) => string | null; const required: Rule = (v) => (v.trim() ? null : 'Required');const minLength = (n: number): Rule => (v) => (v.length >= n ? null : `At least ${n} characters`);const email: Rule = (v) => (/^\S+@\S+\.\S+$/.test(v) ? null : 'Not an email');…GuestCartнаследуетCartи бросает ошибку изcheckout(). Какой принцип SOLID он нарушает и как исправить дизайн?class Cart { protected items: CartItem[] = []; add(item: CartItem) { this.items.push(item); } checkout(api: OrdersApi): Promise<string> { return api.createOrder(this.items); }} // guests can fill a cart but must sign in to payclass GuestCart extends Cart { override async checkout(): Promise<string> { throw new Error('Sign in to check out'); }} async function buyNow(cart: Cart, item: CartItem, api: OrdersApi) { cart.add(item); return cart.checkout(api);}Что такое паттерны Module и Singleton и почему ES-модуль уже является синглтоном?
// before ES modules: an IIFE kept its variables private (the Module pattern)var legacyCounter = (function () { var count = 0; return { increment: function () { return ++count; } };})();…Что такое паттерн Factory и как с помощью фабрики создавать нужный API-клиент для каждого окружения?
export interface ApiClient { get<T>(path: string): Promise<T>;} function httpClient(baseUrl: string): ApiClient { return {…Чем паттерн Adapter отличается от Facade и где во фронтенд-приложении применяется каждый из них?
// what the backend sendsinterface UserDto { user_id: number; full_name: string; created_at: string; // ISO date}…Что такое паттерн Proxy и чем он отличается от объекта
Proxyв JavaScript?interface ExchangeRates { rate(from: string, to: string): Promise<number>;} class HttpExchangeRates implements ExchangeRates { async rate(from: string, to: string) {…Что такое паттерн Decorator и как его реализуют функции-обёртки и декораторы TypeScript вроде
@logged?// a wrapper function: the Decorator pattern for a plain functionfunction withTiming<A extends unknown[], R>(name: string, fn: (...args: A) => Promise<R>) { return async (...args: A): Promise<R> => { const start = performance.now(); try { return await fn(...args);…Чем паттерн Observer отличается от publish/subscribe и где во фронтенд-коде встречается каждый из них?
import { useSyncExternalStore } from 'react'; // Observer: the subject keeps its own listeners and calls them itselffunction createCounterStore() { let count = 0; const listeners = new Set<() => void>();…Найдите баг:
destroy()вызываетoff, но каждая закрытая панель поиска продолжает перерисовываться при каждом изменении стора.class SearchPanel { constructor(readonly store: SearchStore, readonly el: HTMLElement) { store.on('change', this.render.bind(this)); } render() { this.el.textContent = `${this.store.results.length} results`; } destroy() { this.store.off('change', this.render.bind(this)); this.el.remove(); }}Что такое паттерн Mediator и чем он отличается от Observer?
type FieldName = 'country' | 'delivery' | 'isCompany' | 'vatId'; interface FieldState { value: string; disabled: boolean; options?: string[];…Что такое паттерны Strategy и Command и почему в TypeScript оба часто сводятся к функциям или обычным объектам?
// Strategy: how shipping is priced, picked by keytype ShippingStrategy = (weightKg: number) => number; const shipping = { standard: (kg) => 500 + kg * 100, express: (kg) => 1500 + kg * 250,…Какие классические паттерны проектирования JavaScript делает тривиальными благодаря функциям первого класса, замыканиям и модулям, а какие всё ещё требуют проектирования?
Как применить инверсию зависимостей к слою API фронтенда (порты и адаптеры) и когда это не стоит усилий?
// orders/model.ts: the port, in the domain's own termsexport interface Order { id: string; totalCents: number; placedAt: Date;}…Какие антипаттерны чаще всего встречаются во фронтенд-кодовых базах (god store, свалка
utils, неверная абстракция) и как выбраться из них рефакторингом?