وجهان لعملة واحدة: منهج البرمجة الوظيفية والبرمجة كائنية التوجه في TypeScript
\n\nعالم TypeScript هو مكان رائع تمتزج فيه أفضل الممارسات من عوالم مختلفة. هل تساءلت يومًا لماذا يكتب بعض المطورين الكود باستخدام الكلاسات والوراثة، بينما يكتب آخرون دوالًا نقية وتركيبًا؟ والأهم: أي منهج سيجلب فائدة أكبر لمشروعك؟
\n\nفي هذه المقالة، لن نتجادل حول أيهما أفضل. سنحلل البرمجة الوظيفية مقابل البرمجة كائنية التوجه في TypeScript بأمثلة واقعية. ستتعرف متى تستخدم الكلاسات، ومتى تستخدم دوال الترتيب الأعلى، وكيف تجد الوسط الذهبي في التطوير الحديث.
\n\nما هي البرمجة الوظيفية في TypeScript؟
\n\nالبرمجة الوظيفية (FP) هي نموذج تكون فيه اللبنة الأساسية هي الدوال النقية. لا تغير الحالة الخارجية وتعيد دائمًا نفس النتيجة لنفس المدخلات. يدعم TypeScript البرمجة الوظيفية بشكل ممتاز بفضل الكتابة الصارمة وإمكانيات التعامل مع الدوال كبيانات.
\n\nالمبادئ الأساسية للبرمجة الوظيفية في TypeScript
\n- \n
- الثباتية — لا يتم تغيير البيانات، بل يتم إنشاؤها من جديد \n
- الدوال النقية — لا تأثيرات جانبية \n
- التركيب — بناء سلوك معقد من دوال بسيطة \n
- دوال الترتيب الأعلى — دوال تستقبل أو تعيد دوال أخرى \n
// مثال على الدوال النقية والثباتية في TypeScript\ntype User = {\n readonly id: number;\n readonly name: string;\n readonly age: number;\n};\n\nconst addYear = (user: User): User => ({\n ...user,\n age: user.age + 1\n});\n\nconst users: User[] = [\n { id: 1, name: 'Alice', age: 25 },\n { id: 2, name: 'Bob', age: 30 }\n];\n\n// لا تحويرات — ننشئ مصفوفة جديدة\nconst updatedUsers = users.map(addYear);\nconsole.log(users[0].age); // 25 (الأصل لم يتغير)\nconsole.log(updatedUsers[0].age); // 26\n\n\nلاحظ readonly — هذه أداة قوية في TypeScript تساعد في الالتزام بالثباتية على مستوى الأنواع.
ما هي البرمجة كائنية التوجه في TypeScript؟
\n\nالبرمجة كائنية التوجه (OOP) تبنى حول الكائنات التي تجمع بين البيانات والسلوك. يضيف TypeScript إلى JavaScript الوراثة الكلاسيكية، معدّلات الوصول، والواجهات، مما يجعل البرمجة كائنية التوجه أكثر تعبيرًا.
\n\nالمبادئ الأساسية للبرمجة كائنية التوجه في TypeScript
\n- \n
- التغليف — إخفاء الحالة الداخلية عبر
privateوprotected\n - الوراثة — إنشاء تسلسلات هرمية للكلاسات \n
- تعدد الأشكال — واجهة موحدة لتطبيقات مختلفة \n
- التجريد — العمل عبر الواجهات وليس الكلاسات المحددة \n
// مثال على منهج البرمجة كائنية التوجه في TypeScript\nabstract class Animal {\n constructor(protected name: string) {}\n\n abstract makeSound(): string;\n\n public introduce(): string {\n return `I am ${this.name}, and I say ${this.makeSound()}`;\n }\n}\n\nclass Dog extends Animal {\n constructor(name: string) {\n super(name);\n }\n\n public makeSound(): string {\n return 'Woof!';\n }\n}\n\nclass Cat extends Animal {\n constructor(name: string) {\n super(name);\n }\n\n public makeSound(): string {\n return 'Meow!';\n }\n}\n\nconst animals: Animal[] = [new Dog('Rex'), new Cat('Whiskers')];\nanimals.forEach(a => console.log(a.introduce()));\n// I am Rex, and I say Woof!\n// I am Whiskers, and I say Meow!\n\n\nهنا abstract و protected هي ميزات TypeScript غير موجودة في JavaScript العادي. تسمح ببناء بنية صارمة مباشرة على مستوى الأنواع.
مقارنة المنهجين: متى نستخدم أيهما؟
\n\nدعنا نحلل بعض