Абстракция

Абстракция — принцип ООП, при котором наружу выставляется только необходимый интерфейс (что делает объект), скрывая детали реализации (как именно он это делает).

Зачем нужно

Абстракция снижает когнитивную нагрузку: работая с объектом, достаточно знать его API, а не внутреннее устройство. Это упрощает повторное использование кода, позволяет менять реализацию без изменения вызывающего кода и улучшает поддерживаемость системы.

Где используется

  • Скрытие сложности работы с API (обёртка над fetch)
  • Интерфейсы хранилища данных (можно менять localStorage на IndexedDB без правки кода выше)
  • Классы и модули, предоставляющие методы-контракты
  • Функции высшего порядка, скрывающие алгоритм

Примеры

Абстракция через функцию

// Без абстракции: детали реализации везде
const url = 'https://api.example.com/users/42';
const res = await fetch(url, { headers: { Authorization: `Bearer ${token}` } });
const data = await res.json();

// С абстракцией: детали скрыты
async function getUser(id) {
  const res = await fetch(`https://api.example.com/users/${id}`, {
    headers: { Authorization: `Bearer ${getToken}` }
  });
  if (!res.ok) throw new Error(`Ошибка: ${res.status}`);
  return res.json();
}

const user = await getUser(42); // вызывающий код не знает про fetch

Абстракция хранилища

// Абстрактный интерфейс хранилища
class Storage {
  get(key) { throw new Error('Не реализовано'); }
  set(key, value) { throw new Error('Не реализовано'); }
  remove(key) { throw new Error('Не реализовано'); }
}

// Конкретная реализация
class LocalStorage extends Storage {
  get(key) {
    const val = localStorage.getItem(key);
    return val ? JSON.parse(val) : null;
  }
  set(key, value) {
    localStorage.setItem(key, JSON.stringify(value));
  }
  remove(key) {
    localStorage.removeItem(key);
  }
}

// Код выше работает с любой реализацией
class UserService {
  constructor(storage) {
    this.storage = storage; // инъекция зависимости
  }
  saveUser(user) {
    this.storage.set(`user_${user.id}`, user);
  }
  getUser(id) {
    return this.storage.get(`user_${id}`);
  }
}

const service = new UserService(new LocalStorage);
service.saveUser({ id: 1, name: 'Иван' });

Абстракция через замыкание

// Создаём HTTP-клиент, скрывая детали
function createApiClient(baseUrl, token) {
  async function request(method, path, body) {
    const res = await fetch(`${baseUrl}${path}`, {
      method,
      headers: {
        'Content-Type': 'application/json',
        Authorization: `Bearer ${token}`,
      },
      body: body ? JSON.stringify(body) : undefined,
    });
    if (!res.ok) throw new Error(res.statusText);
    return res.json();
  }

  return {
    get: (path) => request('GET', path),
    post: (path, body) => request('POST', path, body),
    put: (path, body) => request('PUT', path, body),
    delete: (path) => request('DELETE', path),
  };
}

const api = createApiClient('https://api.example.com', myToken);
const users = await api.get('/users');

Частые ошибки

  • Слишком ранняя абстракция (over-engineering) — абстрагировать то, что меняется один раз за время жизни проекта, не оправдано; важен баланс.
  • «Утечка» деталей реализации в интерфейс — если публичный API возвращает внутренние структуры (например, сырые объекты БД), абстракция нарушена.
  • Абстракция ради абстракции — создание классов-обёрток без реальной пользы усложняет код.

Тезисы из лекций автора

  • Абстракция — не привилегия ООП. Регистр процессора, переменная, функция, модуль — это всё абстракции. «Мы ничем не можем думать, кроме как абстракциями» (4yO5OS0vPSw).
  • Модель реальности или чистая выдумка. Класс может моделировать реальный мир (Passport, Robot) или быть чистой выдумкой (Socket, EventEmitter, Scheduler). Сокет — НЕ модель розетки, имя просто заимствовано (sQwF6-bYeDM).
  • Абстракция vs Абстрагирование. Абстракция — программный компонент (Socket, EventEmitter). Абстрагирование — процесс моделирования. По-русски удобно различать (r4ReQlVtfgQ).
  • Без инкапсуляции нет абстракции. «В принципе невозможно построить никакого класса, не сделав инкапсуляцию.» Абстракция — что моделируем, инкапсуляция — техника.
  • Анемичная модель. Класс паспорта — только данные, нет и не может быть методов. Это нормально для информационных моделей, но плохо для ООП-стиля. См. Анемичная модель и ООП для домена.

Связанные темы

Источники