مقدمة: لماذا لا يهدأ الجدل بين البرمجة الشيئية والمنهج الوظيفي؟
\n\nإذا كنت قد تساءلت يومًا عن أسلوب البرمجة في C++ الذي تختاره لمشروع جديد، فأنت لست وحدك. الجدل بين البرمجة الوظيفية والمنهج الشيئي في C++ مستمر منذ عقود. من ناحية، لدينا البرمجة الشيئية التقليدية التي تُدرَّس في الجامعات. ومن ناحية أخرى، لدينا التقنيات الوظيفية الحديثة التي جلبتها معايير C++11 و C++14 و C++17 و C++20.
\n\nفي موقع pythonlib.ru، نناقش غالبًا القرارات المعمارية، واليوم حان الوقت لتحليل هذه المسألة بشكل نهائي. أي أسلوب أسرع؟ أيهما أسهل في الصيانة؟ والأهم، هل يمكن الجمع بينهما؟
\n\nفي هذه المقالة، لن نتعصب لصالح نموذج واحد. بدلاً من ذلك، سنحلل أمثلة كود حقيقية، ونعرض إيجابيات وسلبيات كل منهج، ونقدم توصيات عملية. هيا بنا!
\n\nنظرة عامة سريعة على النماذج في C++
\n\nقبل التعمق، دعنا ننعش ذاكرتنا سريعًا حول ما نتحدث عنه.
\n\nالبرمجة الشيئية (OOP)
\n\nتقوم البرمجة الشيئية في C++ على ثلاث ركائز: التغليف، الوراثة، وتعدد الأشكال. تقوم بإنشاء فئات (Classes) تجمع بين البيانات وطرق معالجتها. هذا هو المنهج التقليدي الذي ساد في التسعينيات والألفينيات.
\n\nclass Animal {\npublic:\n virtual void speak() const = 0;\n virtual ~Animal() = default;\n};\n\nclass Dog : public Animal {\npublic:\n void speak() const override {\n std::cout << "Woof!" << std::endl;\n }\n};\n\nclass Cat : public Animal {\npublic:\n void speak() const override {\n std::cout << "Meow!" << std::endl;\n }\n};\n\nvoid makeSound(const Animal& animal) {\n animal.speak();\n}\n\n\nالبرمجة الوظيفية (FP)
\n\nالمنهج الوظيفي في C++ ليس Haskell نقيًا، بل هو استخدام أفكار البرمجة الوظيفية ضمن لغة أمرية. العناصر الأساسية: دوال لامدا، ثبات البيانات، دوال الترتيب الأعلى والتركيب.
\n\nstd::vector<int> numbers = {1, 2, 3, 4, 5};\n\n// أسلوب وظيفي: تصفية وتحويل\nauto result = numbers\n | std::views::filter([](int n) { return n % 2 == 0; })\n | std::views::transform([](int n) { return n * n; });\n\nfor (int n : result) {\n std::cout << n << " "; // الإخراج: 4 16\n}\n\n\nمقارنة عملية: ثلاث مهام نموذجية
\n\nلنأخذ ثلاث مهام حقيقية يواجهها مطور C++، ونرى كيف تحلها البرمجة الشيئية والوظيفية.
\n\nالمهمة 1: معالجة مجموعة بيانات
\n\nالشرط: لدينا قائمة طلبات، نحتاج لتصفية الطلبات باهظة الثمن (السعر > 1000)، وترتيبها حسب التاريخ، وعرض أفضل 5.
\n\nالأسلوب الشيئي:
\n\nclass OrderProcessor {\npublic:\n void addOrder(Order order) { orders_.push_back(std::move(order)); }\n \n std::vector<Order> getTopExpensiveRecent(int count) const {\n auto filtered = orders_;\n filtered.erase(\n std::remove_if(filtered.begin(), filtered.end(),\n [](const Order& o) { return o.price <= 1000; }),\n filtered.end());\n \n std::sort(filtered.begin(), filtered.end(),\n [](const Order& a, const Order& b) {\n return a.date > b.date;\n });\n \n if (filtered.size() > count) {\n filtered.resize(count);\n }\n return filtered;\n }\n \nprivate:\n std::vector<Order> orders_;\n};\n\n\nالأسلوب الوظيفي:
\n\nauto getTopExpensiveRecent(const std::vector<Order>& orders, int count) {\n return orders\n | std::views::filter([](const Order& o) { return o.price >