Go: وظيفي أم كائني التوجه؟ نختار أسلوب البرمجة

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

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

ابدأ الدورة

مقدمة: الجدل الأبدي في عالم Go

\n\n

Go — لغة حطمت القوالب. إنها لا تغفر التعقيد المفرط، ولكنها في الوقت نفسه تمنح المطور حرية لا تصدق. كل من يبدأ في الكتابة بلغة Go (أو ينتقل من Python أو Java) يصطدم عاجلاً أم آجلاً بحائط: «وكيف يكون الصواب؟ الكتابة مثل Java مع الفئات والوراثة أم مثل Haskell مع الدوال الخالية من الآثار الجانبية؟»

\n\n

إفساد: Go ليست لغة كائنية التوجه بحتة ولا وظيفية بحتة. إنها براغماتية. لكن هذا لا يعني أنه لا يمكنك (ولا ينبغي عليك) استخدام كلا النموذجين. في هذه المقالة، سنتعرف على كيفية الجمع بين المنهج الوظيفي والكائني التوجه في Go بحيث يكون كودك قابلاً للقراءة والاختبار وسريعاً. لن نلقي محاضرات، بل سننظر إلى أمثلة حقيقية وأنماط مضادة.

\n\n

إذا كنت تبحث عن أفضل ممارسات Go وتريد فهم كيفية كتابة كود نظيف بهذه اللغة — فأنت في المكان الصحيح.

\n\n

1. المنهج الكائني التوجه في Go: بدون فئات ولكن بروح

\n\n

يعتقد الكثيرون أنه بما أنه لا يوجد class في Go، فلا يوجد OOP فيها. هذه خرافة. البرمجة كائنية التوجه في Go تقوم على ركيزتين: الهياكل (structs) والواجهات (interfaces). لا يوجد وراثة، ولكن يوجد تكوين (composition) الذي يعتبره مبتكرو اللغة أكثر مرونة.

\n\n

الهياكل والطرق

\n

يمكنك تعريف طرق لأي نوع. هذا هو أساس الكود كائني التوجه.

\n\n
package main\n\nimport "fmt"\n\n// تعريف واجهة (عقد)\ntype Notifier interface {\n    Send(message string) error\n}\n\n// هيكل ينفذ الواجهة\ntype EmailNotifier struct {\n    Email string\n}\n\n// طريقة لـ EmailNotifier\nfunc (e EmailNotifier) Send(message string) error {\n    fmt.Printf("إرسال بريد إلكتروني إلى %s: %s\\n", e.Email, message)\n    return nil\n}\n\n// هيكل آخر\ntype SMSNotifier struct {\n    Phone string\n}\n\nfunc (s SMSNotifier) Send(message string) error {\n    fmt.Printf("إرسال رسالة نصية إلى %s: %s\\n", s.Phone, message)\n    return nil\n}\n\n// دالة تقبل أي Notifier (تعدد الأشكال)\nfunc AlertAll(notifiers []Notifier, msg string) {\n    for _, n := range notifiers {\n        n.Send(msg)\n    }\n}\n\nfunc main() {\n    notifiers := []Notifier{\n        EmailNotifier{Email: "user@example.com"},\n        SMSNotifier{Phone: "+1234567890"},\n    }\n    AlertAll(notifiers, "الخادم تعطل!")\n}
\n\n

مزايا OOP في Go:

\n
    \n
  • تعدد الأشكال عبر الواجهات. تكتب دالة AlertAll مرة واحدة، وتعمل مع أي نوع ينفذ Notifier. هذا ارتباط ضعيف.
  • \n
  • الحالة. الهياكل مثالية لنماذج البيانات (User, Order, Config).
  • \n
  • التغليف. الحقول بحرف صغير — خاصة، بحرف كبير — عامة. بسيط وفعال.
  • \n
\n\n

العيوب:

\n
    \n
  • من السهل الانزلاق إلى «أسلوب Java»: إنشاء تسلسلات هرمية عميقة، على الرغم من أن Go لا يدعمها.
  • \n
  • قابلية التغيير (تغيير الحالة) تعقد الاختبار وتصحيح الأخطاء.
  • \n
\n\n

2. البرمجة الوظيفية في Go: النقاء من أجل السرعة

\n\n

الأسلوب الوظيفي في Go ليس حساب لامدا، بل هو مجموعة من المبادئ: الحد الأدنى من الآثار الجانبية، عدم القابلية للتغيير، الدوال كوسائط. مع ظهور الأدوية العامة (Go 1.18+) أصبح هذا الأسلوب أقوى.

\n\n

الدوال النقية وعدم القابلية للتغيير

\n

القاعدة الرئيسية للبرمجة الوظيفية: الدالة تستقبل البيانات، وتعيد بيانات جديدة، لكنها لا تغير أي شيء خارجها.

\n\n
package main\n\nimport "fmt"\n\n// سيء: تغيير الشريحة الواردة (أثر جانبي)\nfunc BadAddPrefix(users []string, prefix string) {\n    for i := range users {\n        users[i] = prefix + users[i]\n    }\n}\n\n// جيد: إرجاع شريحة جديدة (دالة نقية)\                

المدونات

توصيات الكتب