ما هو Dependency Injection؟
Dependency Injection (DI) نمط تصميم يُستخدم لتحقيق Inversion of Control (IoC). الفكرة: بدلاً من أن ينشئ الكائن تبعياته بنفسه، تُحقن فيه من الخارج.
// بدون DI - اقتران قوي
class Logger {
log(message: string) { /* ... */ }
}
class UserService {
private logger = new Logger(); // إنشاء داخلي - اقتران
}
// مع DI - اقتران ضعيف
class UserService {
constructor(private logger: Logger) {} // حقن من الخارج
}
IoC Container
حاوية IoC تدير إنشاء الكائنات وحقن التبعيات آلياً:
import { Container, injectable, inject } from "inversify";
const container = new Container();
@injectable()
class Logger {
log(message: string) {
console.log(`[LOG]: ${message}`);
}
}
@injectable()
class UserService {
constructor(@inject(Logger) private logger: Logger) {}
createUser(name: string) {
this.logger.log(`إنشاء مستخدم: ${name}`);
}
}
container.bind(Logger).toSelf();
container.bind(UserService).toSelf();
DI في NestJS
NestJS يبني على DI بشكل كامل:
@Injectable()
export class UsersService {
constructor(
@InjectRepository(User)
private usersRepository: Repository<User>,
private mailService: MailService,
) {}
async create(dto: CreateUserDto) {
const user = this.usersRepository.save(dto);
await this.mailService.sendWelcome(user);
return user;
}
}
⚠️ مهم: DI يقلل الاقتران ويسهل الاختبار، لكن لا تفرط في استخدامه لكل متغير صغير.
أنواع الحقن
- Constructor Injection - حقن عبر المُنشئ (الأكثر شيوعاً)
- Property Injection - حقن عبر الخاصية
- Method Injection - حقن عبر الدالة
// Constructor Injection
class Service {
constructor(private dep: Dependency) {}
}
// Property Injection
class Service {
@inject(Dependency) private dep!: Dependency;
}
// Method Injection
class Service {
setDependency(dep: Dependency) {
this.dep = dep;
}
}
فوائد DI
- اختبار أسهل: يمكنك تمرير Mock objects بسهولة
- اقتران أقل: الكائنات لا تعتمد على تطبيقات محددة
- إعادة استخدام: يمكن تبديل التطبيقات دون تغيير المستهلك
- إدارة دورة الحياة: الحاوية تتحكم في Singletons و Scoped
🎯 التالي: الأنماط في JavaScript و Node.js