أنماط العمارة في TypeScript: كيف تتوقف عن كتابة "المعكرونة" وتبدأ في العيش
\n\nهل سبق لك أن فتحت مشروعًا على TypeScript كتبته قبل ستة أشهر، وأدركت برعب أنك لا تستطيع فهم الفئات الخاصة بك؟ أو ربما كنت تضيف ميزة جديدة، وكان التطبيق يتعطل في ثلاثة أماكن غير متوقعة؟ مألوف؟ مرحبًا بك في نادي المطورين الذين قرروا ذات مرة أن "هذا يكفي" - ودفعوا الثمن.
\n\nTypeScript ليس مجرد إضافة فوق JavaScript مع أنواع. إنها أداة قوية تسمح لك ببناء أنظمة معقدة وقابلة للتوسع والصيانة. لكن الأنواع وحدها لن تنقذك من الفوضى المعمارية. أنت بحاجة إلى أنماط العمارة - وصفات مجربة عبر الزمن تساعد في تنظيم الكود ليكون مفهومًا وقابلًا للاختبار ومرنًا.
\n\nفي هذه المقالة، سنحلل خمسة أنماط عمارة رئيسية في TypeScript الأكثر استخدامًا في المشاريع الحقيقية. سترى أمثلة على الكود، وستفهم أين ولماذا تستخدم كل نمط، وستتمكن من تطبيقها فورًا في عملك. هيا بنا!
\n\n1. MVC (Model-View-Controller) - كلاسيكيات النوع
\n\nلنبدأ بأشهر نمط. MVC في TypeScript هو تقسيم التطبيق إلى ثلاث طبقات:
\n\n- \n
- Model - البيانات ومنطق الأعمال. \n
- View - العرض (واجهة المستخدم). \n
- Controller - حلقة الوصل، يعالج إدخال المستخدم. \n
في تطبيقات TypeScript، يكون MVC جيدًا بشكل خاص لأنه يمكننا كتابة أنواع صارمة لجميع الطبقات، مما يستبعد الأخطاء في مرحلة التجميع.
\n\nمثال: قائمة مهام بسيطة (Todo List)
\n\n// Model\ninterface Task {\n id: number;\n title: string;\n completed: boolean;\n}\n\nclass TaskModel {\n private tasks: Task[] = [];\n\n addTask(title: string): Task {\n const newTask: Task = {\n id: Date.now(),\n title,\n completed: false,\n };\n this.tasks.push(newTask);\n return newTask;\n }\n\n getTasks(): Task[] {\n return this.tasks;\n }\n}\n\n// View\nclass TaskView {\n render(tasks: Task[]): void {\n console.clear();\n tasks.forEach(task => {\n console.log(`${task.id}: [${task.completed ? 'x' : ' '}] ${task.title}`);\n });\n }\n}\n\n// Controller\nclass TaskController {\n constructor(\n private model: TaskModel,\n private view: TaskView\n ) {}\n\n addTask(title: string): void {\n this.model.addTask(title);\n this.view.render(this.model.getTasks());\n }\n\n showAll(): void {\n this.view.render(this.model.getTasks());\n }\n}\n\n// الاستخدام\nconst model = new TaskModel();\nconst view = new TaskView();\nconst controller = new TaskController(model, view);\ncontroller.addTask('دراسة أنماط TypeScript');\ncontroller.addTask('كتابة مقال');\n\nلماذا هذا رائع؟ يمكنك تغيير View (مثل الانتقال من وحدة التحكم إلى React) دون لمس Model. يمكنك اختبار منطق الأعمال بشكل منفصل عن واجهة المستخدم. تصبح عمارة تطبيق TypeScript شفافة.
\n\n2. Observer - ملك الأحداث
\n\nإذا كان تطبيقك يعتمد على الأحداث (نقرات، استجابات الخادم، مؤقتات)، فإن نمط Observer TypeScript هو أفضل صديق لك. يسمح لكائنات (المشتركين) بمراقبة التغييرات في كائن آخر (الناشر).
\n\nمثال: نظام الإشعارات
\n\n// واجهة المراقب\ninterface Observer {\n update(data: string): void;\n}\n\n// الناشر\nclass NewsPublisher {\n private observers: Observer[] = [];\n\n subscribe(observer: Observer): void {\n this.observers.push(observer);\n }\n\n unsubscribe(observer: Observer): void {\n this.observers = this.observers.filter(obs => obs !== observer);\n }\n\n publishNews(news: string): void {\n this.observers.forEach(obs => obs.update(news));\n }\n}\n\n// مراقب محدد: إشعار البريد الإلكتروني\nclass Em