Заканчиваем серии постов про SOLID! Сегодня разберём последнюю букву - D, которая расшифровывается как Dependency Inversion Principle (Принцип инверсии зависимостей).
О чём этот принцип?
Высокоуровневые модули не должны зависеть от низкоуровневых. Оба должны зависеть от абстракций. А абстракции не должны зависеть от деталей — детали зависят от абстракций.
Если проще - зависите от интерфейсов, а не от конкретных классов. Это делает код гибким и независимым от деталей реализации.
Пример плохого подхода:
Как улучшить?
Введём интерфейс и передадим зависимость через конструктор:
Теперь
Что это даёт?
- Легко менять реализацию (база, файл, API) без правок в сервисе.
- Подставляйте моки для тестов.
- Зависимости явные, меньше связей.
#BestPractices #JavaScript #typescript
О чём этот принцип?
Высокоуровневые модули не должны зависеть от низкоуровневых. Оба должны зависеть от абстракций. А абстракции не должны зависеть от деталей — детали зависят от абстракций.
Если проще - зависите от интерфейсов, а не от конкретных классов. Это делает код гибким и независимым от деталей реализации.
Пример плохого подхода:
class Database {
save(data: string): void {
console.log(`Сохранено в базе: ${data}`);
}
}
class UserService {
private db = new Database();
saveUser(user: string): void {
this.db.save(user);
}
}
const service = new UserService();
service.saveUser("Alice"); // Сохранено в базе: Alice
UserService жёстко привязан к Database. Хотите сохранить данные в файл или API? Придётся переписывать UserService.Как улучшить?
Введём интерфейс и передадим зависимость через конструктор:
interface Storage {
save(data: string): void;
}
class Database implements Storage {
save(data: string): void {
console.log(`Сохранено в базе: ${data}`);
}
}
class FileStorage implements Storage {
save(data: string): void {
console.log(`Сохранено в файл: ${data}`);
}
}
class UserService {
constructor(private storage: Storage) {}
saveUser(user: string): void {
this.storage.save(user);
}
}
const dbService = new UserService(new Database());
dbService.saveUser("Alice"); // Сохранено в базе: Alice
const fileService = new UserService(new FileStorage());
fileService.saveUser("Bob"); // Сохранено в файл: Bob
Теперь
UserService зависит от абстракции Storage.Что это даёт?
- Легко менять реализацию (база, файл, API) без правок в сервисе.
- Подставляйте моки для тестов.
- Зависимости явные, меньше связей.
#BestPractices #JavaScript #typescript
🔥10👍6
Привет! Недавно мы разбирали нативный метод
Задача
Дан массив объектов:
Нужно сгруппировать по возрасту:
Решение через
Как работает?
1.
2. Для каждого item вычисляем ключ через
3. Если ключа нет в
4. Добавляем
5. Возвращаем обновлённый
#JavaScript #interview
Object.groupBy, а сегодня разберём задачу с реализацией кастомного groupBy. Задача
Дан массив объектов:
const users = [
{ name: 'Алиса', age: 21 },
{ name: 'Макс', age: 25 },
{ name: 'Ваня', age: 21 },
];
Нужно сгруппировать по возрасту:
groupBy(users, user => user.age);
// Результат:
// {
// 21: [{ name: 'Алиса', age: 21 }, { name: 'Ваня', age: 21 }],
// 25: [{ name: 'Макс', age: 25 }]
// }
Решение через
reduce:
function groupBy(array, fn) {
return array.reduce((acc, item) => {
const key = fn(item);
(acc[key] ||= []).push(item);
return acc;
}, {});
}
Как работает?
1.
reduce накапливает объект acc.2. Для каждого item вычисляем ключ через
fn(item).3. Если ключа нет в
acc, создаём массив.4. Добавляем
item в этот массив.5. Возвращаем обновлённый
acc.#JavaScript #interview
🔥9👍4