أنماط التصميم في TypeScript: متى تنقذ المشروع ومتى تعيق

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

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

ابدأ الدورة

أنماط التصميم في TypeScript: متى ولماذا

\n\n

تخيل أنك تبني منزلاً. يمكنك وضع الطوب بشكل عشوائي، وعلى الأرجح لن ينهار. ولكن هل سيكون مريحاً للعيش فيه؟ على الأرجح لا. هندسة البرمجيات هي نفس البناء، ولكن بدلاً من الطوب لدينا الفئات والدوال. أنماط التصميم في TypeScript هي مخططات مجربة للمهام المعمارية النمطية. ولكن، مثل أي أداة، يجب استخدامها بحكمة.

\n\n

في هذه المقالة، لن نعيد سرد النظرية الجافة من كتب GoF (عصابة الأربعة). بدلاً من ذلك، سنحلل أي أنماط تصميم TypeScript مطلوبة حقاً في التطوير الحديث، ومتى تنقذ المشروع، ومتى تسبب الصداع فقط. هيا بنا!

\n\n

لماذا يغير TypeScript قواعد اللعبة؟

\n\n

قبل الغوص في الأنماط، دعنا نتذكر الميزة الرئيسية لـ TypeScript - الكتابة الثابتة (Static Typing). في JavaScript، كنا نستخدم الأنماط غالباً لتعويض الطبيعة الديناميكية للغة. على سبيل المثال، ساعد طريقة المصنع (Factory Method) في إخفاء تعقيد إنشاء الكائنات. في TypeScript، غالباً ما يتم حل هذا التعقيد ببساطة باستخدام الواجهات (Interfaces) والأدوية (Generics).

\n\n

ولكن هذا لا يعني أن الأنماط قد ماتت. على العكس، TypeScript يجعلها أكثر تعبيراً وأماناً. يقوم المترجم (Compiler) بالتحقق من أنك قمت بتنفيذ الهيكل بشكل صحيح، ولا يسمح لك بارتكاب أخطاء غبية. هنا يكشف TypeScript قوة أنماط GoF.

\n\n

أفضل 5 أنماط ستستخدمها في أغلب الأحيان

\n\n

1. Singleton (المفرد) - عندما يكون الواحد جيداً والاثنان زائدين

\n\n

متى تستخدم: تحتاج إلى نسخة واحدة بالضبط من الفئة للتطبيق بأكمله. الأمثلة الكلاسيكية هي المسجل (Logger)، إعدادات التطبيق، الاتصال بقاعدة البيانات.

\n\n

لماذا في TypeScript: TypeScript يسمح بجعل Singleton آمناً للخيوط (Thread-safe) وآمناً للأنواع (Type-safe). بدونه، تخاطر بتوليد عشرات الكائنات التي ستستهلك الذاكرة وتخلط الحالة.

\n\n

مثال كود:

\n\n
class DatabaseConnection {\n    private static instance: DatabaseConnection;\n    private connectionString: string;\n\n    private constructor(connectionString: string) {\n        this.connectionString = connectionString;\n        // محاكاة الاتصال\n        console.log(`اتصال بـ ${connectionString}`);\n    }\n\n    static getInstance(connectionString: string): DatabaseConnection {\n        if (!DatabaseConnection.instance) {\n            DatabaseConnection.instance = new DatabaseConnection(connectionString);\n        }\n        return DatabaseConnection.instance;\n    }\n\n    query(sql: string): void {\n        console.log(`تنفيذ الاستعلام: ${sql}`);\n    }\n}\n\n// الاستخدام\nconst db = DatabaseConnection.getInstance('postgres://localhost:5432/mydb');\ndb.query('SELECT * FROM users');\n\n// محاولة إنشاء اتصال آخر سيعيد نفس النسخة\nconst db2 = DatabaseConnection.getInstance('postgres://localhost:5432/mydb');\nconsole.log(db === db2); // true
\n\n

النمط المضاد: لا تجعل Singleton من أجل Singleton. إذا كان الكائن يمكن أن يوجد في عدة نسخ بحالات مختلفة (مثل اتصالات مختلفة بقواعد بيانات مختلفة)، فإن Singleton هو شر.

\n\n

2. Factory Method (طريقة المصنع) - إنشاء الكائنات بدون ألم

\n\n

متى تستخدم: لا تعرف مسبقاً أي كائن بالضبط تحتاج إلى إنشائه. أو أن عملية الإنشاء معقدة وتتطلب منطقاً.

\n\n

لماذا في TypeScript: طريقة المصنع تتناسب بشكل ممتاز مع الواجهات والأدوية. تحصل على مرونة دون فقدان الأنواع.

\n\n

مثال كود:

\n\n
// منتج مجرد\ninterface Notification {\n    send(message: string): void;\n}\n\n// منتجات محددة\nclass EmailNotification implements Notification {\n    send(message: string): void {\n        console.log(`إرسال بريد إلكتروني: ${message}`);\n    }                

المدونات

توصيات الكتب