Senior
Kako rešiti problem korišćenja zavisnosti perifernih komponenti u jezgru?
sobes.tech АИ
Одговор од АИ
Решавање проблема коришћења зависности периферних компоненти (адаптери, интерфејси) у језгру (доментној логици) у архитектурама као што су Чиста архитектура или DDD, може се постићи помоћу принципа Инверзија зависности (Dependency Inversion Principle - DIP).
Суштина DIP:
- Модули вишег нивоа не треба да зависе од модула нижег нивоа. Обоје треба да зависе од апстракција.
- Апстракције не треба да зависе од детаља. Детали треба да зависе од апстракција.
Практична примена:
- Језгро објављује интерфејсе: Језгро дефинише апстракције (интерфејсе или апстрактне класе) које описују потребне функције периферних компоненти.
- Периферне компоненте реализују интерфејсе: Спољашњи модули (адаптери за базе података, HTTP клијенти, фајл системи итд.) реализују ове интерфејсе.
- Уметање зависности (Dependency Injection - DI): Периферне компоненте се уметају у језгро изван, обично на вишем нивоу апликације (нпр. у композиционом корену или коришћењем DI контејнера). Језгро ради само са апстракцијама.
Пример коришћења DIP у Node.js:
Замислите да имамо језгро које треба приступ подацима.
// src/domain/interfaces/UserRepository.ts
// Језгро објављује интерфејс
export interface UserRepository {
getUserById(id: string): Promise<User | null>;
}
// src/domain/entities/User.ts
// Језгро ентитет
export class User {
constructor(public id: string, public name: string) {}
}
// src/domain/usecases/GetUserUseCase.ts
// Језгро use case зависи од апстракције UserRepository
import { UserRepository } from '../interfaces/UserRepository';
import { User } from '../entities/User';
export class GetUserUseCase {
constructor(private userRepository: UserRepository) {}
async execute(id: string): Promise<User | null> {
return this.userRepository.getUserById(id);
}
}
// src/infrastructure/database/MongoDbUserRepository.ts
// Периферни компонент који реализује интерфејс језгра
import { UserRepository } from '../../domain/interfaces/UserRepository';
import { User } from '../../domain/entities/User';
export class MongoDbUserRepository implements UserRepository {
// Овде ће бити логика комуникације са MongoDB
async getUserById(id: string): Promise<User | null> {
console.log(`Добијање корисника са id ${id} из MongoDB...`);
// Модел симулације добијања података
if (id === '123') {
return new User('123', 'John Doe');
}
return null;
}
}
// src/app/CompositionRoot.ts
// Композициони корен сабира зависности
import { GetUserUseCase } from '../domain/usecases/GetUserUseCase';
import { MongoDbUserRepository } from '../infrastructure/database/MongoDbUserRepository';
// Уметање зависности: Језгро добија реализацију MongoDbUserRepository преко интерфејса
const userRepository = new MongoDbUserRepository();
const getUserUseCase = new GetUserUseCase(userRepository);
// Сада можемо користити use case
async function run() {
const user = await getUserUseCase.execute('123');
if (user) {
console.log(`Пронађен корисник: ${user.name}`);
} else {
console.log('Корисник није пронађен');
}
}
run();
Предности овог приступа:
- Независност језгра: Језгро не зна за конкретне реализације периферних компоненти.
- Тестираљивост: Језгро је лако тестирати, замењујући мок-реализације интерфејса.
- Флексибилност: Лако је заменити једну реализацију (нпр. базу података) другом, без промене кода језгра.
- Подршка: Олакшава одржавање и измене кода.