Вопрос проверяет понимание принципов абстракции и инверсии зависимостей при проектировании репозиториев в сервисном слое.
В сервисном слое репозиторий должен быть представлен интерфейсом (абстракцией), а не конкретным классом. Это следует из принципа инверсии зависимостей (Dependency Inversion Principle) — модули верхнего уровня не должны зависеть от модулей нижнего уровня, оба должны зависеть от абстракций.
// Абстракция (интерфейс)
interface UserRepository {
findById(id: string): Promise<User | null>;
save(user: User): Promise<void>;
}
// Конкретная реализация для PostgreSQL
class PostgresUserRepository implements UserRepository {
async findById(id: string): Promise<User | null> {
// SQL запрос к БД
}
async save(user: User): Promise<void> {
// INSERT запрос
}
}
// Сервис зависит от абстракции
class UserService {
constructor(private repo: UserRepository) {}
async getUser(id: string) {
return this.repo.findById(id);
}
}Данный подход используется в большинстве современных фреймворков (Spring, NestJS, ASP.NET Core) и рекомендуется в DDD (Domain-Driven Design). Он особенно полезен в крупных проектах, где требуется тестирование и гибкость.
Вывод: Используйте абстракцию репозитория в сервисе всегда, когда возможна смена хранилища или нужна изоляция для тестов. Это делает архитектуру чище и устойчивее к изменениям.