حقن التبعيات في TypeScript: دليل بسيط للمبتدئين

مدرب بايثون أونلاين للمبتدئين

تعلم Python بسهولة دون إرهاق نظري. حل مهام عملية مع التحقق التلقائي واكتب الكود مباشرة في المتصفح.

ابدأ الدورة

Dependency Injection في TypeScript: للمبتدئين

\n\n

في عالم تطوير البرمجيات، غالبًا ما يُستخدم مصطلح Dependency Injection (DI)، أو حقن التبعيات. بالنسبة للمطور المبتدئ في TypeScript، قد يبدو هذا مخيفًا، لكنه في الواقع نمط بسيط وقوي يجعل الكود الخاص بك أنظف، وأكثر قابلية للاختبار، وأسهل في الصيانة. في هذه المقالة، سنشرح ما هو DI، ولماذا هو مطلوب، وكيفية تطبيقه في TypeScript عمليًا.

\n\n

ما هو Dependency Injection؟

\n\n

تخيل أنك تقوم بتجميع جهاز كمبيوتر. بدلاً من دمج المعالج مباشرة في اللوحة الأم في المصنع، تترك فتحة يمكنك إدخال أي معالج متوافق فيها. يعمل Dependency Injection بنفس المبدأ: بدلاً من أن يقوم الفصل (class) بإنشاء تبعياته بنفسه (مثل قاعدة بيانات أو عميل HTTP)، فإنه يستقبلها من الخارج.

\n\n

بعبارات بسيطة، DI هو عندما لا يقوم الكائن بإنشاء "مساعديه" داخليًا، بل يستقبلهم جاهزين عبر المُنشئ (constructor) أو طريقة (method).

\n\n

المشكلة بدون DI: الاقتران الشديد (Tight Coupling)

\n\n

لننظر إلى مثال شائع في المشاريع الحقيقية:

\n\n
class UserService {\n    private database: MySQLDatabase;\n\n    constructor() {\n        this.database = new MySQLDatabase(); // اقتران شديد!\n    }\n\n    getUser(id: number) {\n        return this.database.findUserById(id);\n    }\n}
\n\n

هنا، UserService مرتبط بشدة بـ MySQLDatabase. إذا أردت التبديل إلى PostgreSQL أو كتابة اختبارات وحدة (unit tests) باستخدام قاعدة بيانات وهمية، فسيتعين عليك إعادة كتابة الفصل بأكمله. هذا ينتهك مبدأ Open-Closed من SOLID.

\n\n

الحل باستخدام DI: المرونة وقابلية الاختبار

\n\n

الآن، دعنا نعيد كتابة نفس الفصل باستخدام DI:

\n\n
interface Database {\n    findUserById(id: number): User | null;\n}\n\nclass UserService {\n    constructor(private database: Database) {} // التبعية تُمرر من الخارج\n\n    getUser(id: number) {\n        return this.database.findUserById(id);\n    }\n}\n\n// الاستخدام\nconst mySQL = new MySQLDatabase();\nconst service = new UserService(mySQL); // حقن التبعية
\n\n

الآن، UserService لا يعرف أي قاعدة بيانات يعمل معها. يمكنك بسهولة استبدال MySQLDatabase بـ PostgreSQLDatabase أو MockDatabase للاختبارات.

\n\n

الطرق الأساسية لحقن التبعيات

\n\n

في TypeScript، هناك ثلاث طرق رئيسية لحقن التبعيات. دعنا نستعرض كلًا منها.

\n\n

1. الحقن عبر المُنشئ (Constructor Injection)

\n\n

هذه هي الطريقة الأكثر شيوعًا والموصى بها. يتم تمرير التبعيات عبر مُنشئ الفصل.

\n\n
class Logger {\n    log(message: string) {\n        console.log(`[LOG]: ${message}`);\n    }\n}\n\nclass OrderService {\n    constructor(private logger: Logger) {}\n\n    createOrder(data: any) {\n        this.logger.log('Order created');\n        // منطق إنشاء الطلب\n    }\n}\n\nconst logger = new Logger();\nconst orderService = new OrderService(logger);
\n\n

2. الحقن عبر الخصائص (Property Injection)

\n\n

يتم تعيين التبعية مباشرة إلى خاصية الكائن بعد إنشائه. يُستخدم بشكل أقل شيوعًا لأنه قد يؤدي إلى تهيئة غير كاملة للكائن.

\n\n
class EmailService {\n    sendEmail(to: string, message: string) {\n        console.log(`Email sent to ${to}: ${message}`);\n    }\n}\n\nclass NotificationService {\n    emailService!: EmailService; // تأكيد النوع\n\n    notifyUser(user: string) {\n        this.emailService.sendEmail(user, 'Hello!');\n    }\n}\n\nconst notification = new NotificationService();\nnotification.emailService = new EmailService(); // تعيين الخاصية\nnotification.notifyUser('user@example.com');
\n\n

3. الحقن عبر الطريقة (Method Injection)

\n\

المدونات

توصيات الكتب