Sobes.tech
Senior

Yadroda periferik komponentlar bog'liqliklaridan foydalanish muammosini qanday hal qilish mumkin?

sobes.tech AI

AIdan javob

Periferiy komponentlarining (adapterlar, interfeyslar) bog'lamalaridan foydalanish muammosini, masalan, Toza Arxitektura yoki DDD kabi arxitekturalarda, Bog'lamalarni Teskari O'zgartirish Prinsipi (Dependency Inversion Principle - DIP) yordamida hal qilish mumkin.

DIP ning mohiyati:

  1. Yuqori darajadagi modullar pastki darajadagi modullarga bog'liq bo'lmasligi kerak. Ikkala ham abstraktsiyalarga bog'liq bo'lishi kerak.
  2. Abstraktsiyalar detallarga bog'liq bo'lmasligi kerak. Detallar abstraktsiyalarga bog'liq bo'lishi kerak.

Amaliy qo'llanma:

  • Yadro interfeyslarni e'lon qiladi: Yadro periferik komponentlarning zarur funksiyalarini tavsiflovchi abstraktsiyalarni (interfeyslar yoki abstrakt sinflar) belgilaydi.
  • Periferik komponentlar interfeyslarni amalga oshiradi: Tashqi modullar (ma'lumotlar bazalari uchun adapterlar, HTTP mijozlari, fayl tizimlari va boshqalar) bu interfeyslarni amalga oshiradi.
  • Bog'lamalarni injektsiya qilish (Dependency Injection - DI): Periferik komponentlar tashqaridan yadroga injektsiya qilinadi, odatda, ilovaning yuqori darajasida (masalan, kompozitsiya ildizi yoki DI konteyneridan foydalanib). Yadro faqat abstraktsiyalar bilan ishlaydi.

Node.js da DIP dan foydalanish misoli:

Faraz qilaylik, bizda ma'lumotlarga kirish uchun yadro bor.

// src/domain/interfaces/UserRepository.ts
// Yadro interfeysni e'lon qiladi
export interface UserRepository {
  getUserById(id: string): Promise<User | null>;
}
// src/domain/entities/User.ts
// Yadro obyekti
export class User {
  constructor(public id: string, public name: string) {}
}
// src/domain/usecases/GetUserUseCase.ts
// Yadro foydalanishi, UserRepository abstraktsiyasiga bog'liq
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
// Peryferik komponent, yadro interfeysini amalga oshiradi
import { UserRepository } from '../../domain/interfaces/UserRepository';
import { User } from '../../domain/entities/User';

export class MongoDbUserRepository implements UserRepository {
  // Bu yerda MongoDB bilan o'zaro aloqaning logikasi bo'ladi

  async getUserById(id: string): Promise<User | null> {
    console.log(`Fetching user with id ${id} from MongoDB...`);
    // Ma'lumotlarni olishni simulyatsiya qilish
    if (id === '123') {
      return new User('123', 'John Doe');
    }
    return null;
  }
}
// src/app/CompositionRoot.ts
// Kompozitsiya ildizi bog'lamalarni yig'adi
import { GetUserUseCase } from '../domain/usecases/GetUserUseCase';
import { MongoDbUserRepository } from '../infrastructure/database/MongoDbUserRepository';

// Bog'lamalarni injektsiya qilish: Yadro MongoDbUserRepository amalga oshmasini interfeys orqali oladi
const userRepository = new MongoDbUserRepository();
const getUserUseCase = new GetUserUseCase(userRepository);

// Endi biz foydalanish holatini ishlatishimiz mumkin
async function run() {
  const user = await getUserUseCase.execute('123');
  if (user) {
    console.log(`Found user: ${user.name}`);
  } else {
    console.log('User not found');
  }
}

run();

Ushbu yondashuvning afzalliklari:

  • Yadro mustaqilligi: Yadro aniq periferik komponentlarning amalga oshirishlarini bilmaydi.
  • Test qilish imkoniyati: Yadro interfeyslarning mock amalga oshirishlarini o'rnatib, test qilish oson.
  • Moslashuvchanlik: Bir amalga oshirishni (masalan, ma'lumotlar bazasini) boshqasiga oson almashtirish mumkin, yadro kodini o'zgartirmasdan.
  • Qo'llab-quvvatlash: Kodni saqlash va o'zgartirish osonlashadi.