Абстракция
Абстракция — принцип ООП, при котором наружу выставляется только необходимый интерфейс (что делает объект), скрывая детали реализации (как именно он это делает).
Зачем нужно
Абстракция снижает когнитивную нагрузку: работая с объектом, достаточно знать его 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).
- Без инкапсуляции нет абстракции. «В принципе невозможно построить никакого класса, не сделав инкапсуляцию.» Абстракция — что моделируем, инкапсуляция — техника.
- Анемичная модель. Класс паспорта — только данные, нет и не может быть методов. Это нормально для информационных моделей, но плохо для ООП-стиля. См. Анемичная модель и ООП для домена.
Связанные темы
- _MOC ООП
- Инкапсуляция
- Инкапсуляция
- constructor -- инициализация
- Замыкания (Closures)
- Анемичная модель и ООП для домена
- Composition Pattern
Источники
- Timur · ООП построение абстракций, инкапсуляция и сокрытие (2020-03-03, 28 мин) — главный
- Timur · Object-oriented programming (2020-02-26)
- Timur · Have Objects Failed? Or What's Wrong With OOP (2019-05-23)
- javascript.info — Классы
- MDN — ООП для начинающих