منذ وقت ليس ببعيد ، ظهرت العديد من المنشورات على المحور الذي يتناقض مع المقاربة الوظيفية والموضوعية ، والتي ولدت في التعليقات نقاشًا ساخنًا حول ما هي عليه بالفعل - البرمجة الموجهة للكائنات وكيف تختلف عن الوظيفية. أريد ، مع بعض التأخير ، أن أشارك الآخرين ما يفكر به روبرت مارتن ، المعروف أيضًا باسم العم بوب ، في هذا الأمر.
خلال السنوات القليلة الماضية ، تمكنت مرارًا وتكرارًا من البرمجة جنبًا إلى جنب مع الأشخاص الذين يدرسون البرمجة الوظيفية والذين كانوا متحيزين تجاه OOP. يتم التعبير عن هذا عادةً في شكل عبارات مثل: "حسنًا ، هذا يشبه إلى حد كبير شيء ما".
أعتقد أن هذا يأتي من الاعتقاد بأن FP و OOP يستبعد كل منهما الآخر. يبدو أن الكثيرين يعتقدون أنه إذا كان البرنامج يعمل ، فهو ليس موجهًا للكائنات. أعتقد أن تشكيل مثل هذا الرأي هو نتيجة منطقية لدراسة شيء جديد.
عندما نتعامل مع تقنية جديدة ، غالبًا ما نبدأ في تجنب التقنيات القديمة التي استخدمناها من قبل. هذا أمر طبيعي ، لأننا نعتقد أن التقنية الجديدة "أفضل" وبالتالي فإن التقنية القديمة ربما تكون "أسوأ".
في هذا المنشور ، هناك ما يبرره في الرأي القائل بأنه على الرغم من أن OOP و FP متعامدات ، إلا أنها ليست مفاهيم متبادلة. أن برنامج وظيفي جيد يمكن (وينبغي) أن يكون وجوه المنحى. وأن البرنامج الجيد الموجه نحو الكائنات يمكن (وينبغي) أن يكون وظيفيًا. ولكن من أجل القيام بذلك ، يتعين علينا تحديد الشروط.
ما هو OOP؟
سوف أتناول القضية من منظور الاختزال. هناك العديد من التعريفات الصحيحة لـ OOP التي تغطي العديد من المفاهيم والمبادئ والتقنيات والأنماط والفلسفات. أنوي تجاهلها والتركيز على الملح نفسه. هنا ، هناك حاجة إلى الاختزال لأن كل هذه الثروة من الفرص المحيطة بـ OOP ليست شيئًا خاصًا بـ OOP ؛ انها مجرد جزء من ثروة من الفرص الموجودة في تطوير البرمجيات بشكل عام. هنا سأركز على جزء من OOP ، الذي هو تعريف وغير قابل للنقل.
انظر إلى تعبيرين:
1: f (o) ؛ 2: من () ؛
ما هو الفرق؟
من الواضح أنه لا يوجد فرق دلالي. الفرق كله هو تماما في بناء الجملة. ولكن يبدو أحدهما إجرائيًا ، والآخر موجه نحو الكائن. هذا لأننا معتادون على حقيقة أنه بالنسبة للتعبير 2. يعني ضمنيًا دلالات سلوك خاصة لا تحتوي على التعبير 1. دلالات السلوك المحددة هذه هي تعدد الأشكال.
عندما نرى التعبير 1. نرى الدالة f ، والتي تسمى التي يتم نقل الكائن o إليها . هذا يعني أن هناك وظيفة واحدة فقط تسمى f ، وليست حقيقة أنها عضو في المجموعة المعيارية للوظائف المحيطة بـ o.
من ناحية أخرى ، عندما نرى التعبير 2. نرى كائنًا يحمل الاسم o تُرسل إليه رسالة تحمل الاسم f . نتوقع أنه قد يكون هناك أنواع أخرى من الكائنات التي تتلقى الرسالة f ، وبالتالي لا نعرف السلوك المحدد المتوقع من f بعد المكالمة. يعتمد السلوك على النوع o. وهذا هو ، و هو متعدد الأشكال.
هذه الحقيقة التي نتوقعها من أساليب السلوك المتعدد الأشكال هي جوهر البرمجة الموجهة للكائنات. هذا تعريف مختزل ولا يمكن إزالة هذه الخاصية من OOP. OOP دون تعدد الأشكال ليست OOP. جميع خصائص OOP الأخرى ، مثل تغليف البيانات والأساليب المرتبطة بهذه البيانات وحتى الميراث ، ترتبط أكثر بالتعبير 1. من التعبير 2.
المبرمجون الذين يستخدمون C و Pascal (وحتى إلى حد ما Fortran و Cobol) قاموا دائمًا بإنشاء أنظمة للوظائف والهياكل المغلفة. لإنشاء مثل هذه الهياكل ، لا تحتاج حتى إلى لغة برمجة موجهة للكائنات. التغليف وحتى الميراث البسيط في مثل هذه اللغات واضح وطبيعي. (في C وباسكال بشكل طبيعي أكثر من غيرها)
لذلك ، ما يميز برامج OOP حقًا عن البرامج غير OOP هو تعدد الأشكال.
قد ترغب في القول بأن تعدد الأشكال يمكن أن يتم ببساطة عن طريق استخدام المفتاح f داخل أو سلاسل طويلة / if. هذا صحيح ، لذلك أنا بحاجة إلى وضع قيود أخرى على OOP.
استخدام تعدد الأشكال لا ينبغي أن يخلق اعتماد المتصل على ما يسمى.
لشرح هذا ، دعونا ننظر مرة أخرى في التعبيرات. يبدو التعبير 1: f (o) يعتمد على الدالة f في مستوى التعليمات البرمجية المصدر. نخلص إلى هذا الاستنتاج لأننا نفترض أيضًا أن f هو واحد فقط وبالتالي يجب على المتصل معرفة ذلك.
ومع ذلك ، عندما ننظر إلى Expression 2. of () فإننا نفترض شيئًا آخر. نحن نعلم أنه يمكن أن يكون هناك العديد من إنجازات f ، ونحن لا نعرف أيًا من هذه الوظائف f ستسمى فعليًا. لذلك ، تكون شفرة المصدر التي تحتوي على التعبير 2 مستقلة عن الوظيفة التي يتم استدعاؤها عند مستوى الكود المصدر.
وبشكل أكثر تحديدًا ، هذا يعني أن الوحدات (الملفات ذات الكود المصدري) التي تحتوي على استدعاءات دالة متعددة الأشكال يجب ألا تشير إلى الوحدات (الملفات ذات الكود المصدري) التي تحتوي على تنفيذ هذه الوظائف. لا يمكن أن يكون هناك أي تضمين أو استخدام أو طلب أو أي كلمات رئيسية أخرى تجعل بعض ملفات التعليمات البرمجية المصدر تعتمد على الآخرين.
لذلك ، تعريفنا الاختزالي لـ OOP هو:
تقنية تستخدم تعدد الأشكال الديناميكي لاستدعاء الوظائف ولا تنشئ تبعيات المتصل على ما يسمى في مستوى الكود المصدر.
ما هو AF؟
ومرة أخرى ، سأستخدم نهج الاختزال. FP لها تقاليد وتاريخ غني ، جذورها أعمق من البرمجة نفسها. هناك مبادئ وتقنيات ونظريات وفلسفات ومفاهيم تتخلل هذا النموذج. سوف أتجاهل كل هذا وأذهب مباشرة إلى الجوهر ، إلى الخاصية المتأصلة التي تفصل FP عن الأنماط الأخرى. ومن هنا:
f (a) == f (b) إذا كانت == b.
في برنامج وظيفي ، يعطي استدعاء دالة بنفس الوسيطة النتيجة نفسها بغض النظر عن مدة تشغيل البرنامج. وهذا ما يسمى أحيانا الشفافية المرجعية.
يستنتج مما سبق أن f يجب ألا يغير أجزاء الحالة العالمية التي تؤثر على سلوك f. علاوة على ذلك ، إذا قلنا أن f يمثل جميع الوظائف في النظام - أي ، يجب أن تكون جميع الوظائف في النظام شفافة مرجعية - فلا يمكن لأي وظيفة في النظام تغيير الحالة العالمية. لا يمكن لأي وظيفة أن تفعل أي شيء يمكن أن يؤدي إلى وظيفة أخرى من النظام تقوم بإرجاع قيمة مختلفة بنفس الوسيطات.
هذا له نتيجة أعمق - لا يمكن تغيير القيمة المحددة. وهذا هو ، لا يوجد مشغل المهمة.
إذا نظرت بعناية في هذا البيان ، فيمكنك التوصل إلى استنتاج مفاده أن البرنامج الذي يتألف من وظائف شفافة فقط لا يمكنه فعل أي شيء - لأن أي سلوك مفيد للنظام يغير حالة شيء ما ؛ حتى لو كان مجرد حالة الطابعة أو العرض. ومع ذلك ، إذا استثنينا الحديد من متطلبات الشفافية المرجعية وجميع عناصر العالم من حولنا ، اتضح أنه يمكننا إنشاء أنظمة مفيدة للغاية.
التركيز ، بطبيعة الحال ، في العودية. النظر في وظيفة تأخذ هيكل مع الدولة كوسيطة. تتكون هذه الوسيطة من جميع معلومات الحالة التي تحتاج إليها وظيفة ما. عند الانتهاء من العمل ، تقوم الوظيفة بإنشاء هيكل جديد مع حالة تختلف محتوياتها عن سابقتها. ومع الإجراء الأخير ، تطلق الدالة نفسها على بنية جديدة كوسيطة.
هذه مجرد واحدة من الحيل البسيطة التي يمكن أن يستخدمها أي برنامج وظيفي لتخزين تغييرات الحالة دون الحاجة إلى تغيير الحالة [1].
لذلك ، تعريف اختزال البرمجة الوظيفية:
الشفافية المرجعية - لا يمكنك إعادة تعيين القيم.
FP vs OOP
في هذه المرحلة ، ينظر كل من مؤيدي OOP وأنصار FI إلي بالفعل من خلال مشاهد بصرية. الاختزالية ليست أفضل طريقة لتكوين صداقات. لكن في بعض الأحيان يكون من المفيد. في هذه الحالة ، أعتقد أنه من المفيد تسليط الضوء على holivar المضادة لل OOP.
من الواضح أن تعريفي الاختزالي اللذين اخترتهما متعامدان تمامًا. تعدد الأشكال والشفافية المرجعية ليس لهما علاقة ببعضهما البعض. أنها لا تتقاطع بأي شكل من الأشكال.
لكن التعامدية لا تعني الإقصاء المتبادل (اسأل جيمس كليرك ماكسويل). من الممكن تمامًا إنشاء نظام يستخدم تعدد الأشكال الديناميكي والشفافية المرجعية. هذا ليس ممكنًا فقط ، إنه صحيح وجيد!
لماذا هذا المزيج جيد؟ لنفس الأسباب بالضبط أن كلا من مكوناته! الأنظمة المبنية على تعدد الأشكال الديناميكي جيدة لأن لديها اتصال منخفض. التبعيات يمكن قلبها ووضعها على جوانب مختلفة من الحدود المعمارية. يمكن اختبار هذه الأنظمة باستخدام Moki و Fake وأنواع أخرى من اختبار الزوجي. يمكن تعديل الوحدات النمطية دون إجراء تغييرات على الوحدات النمطية الأخرى. لذلك ، هذه الأنظمة أسهل في التعديل والتحسين.
الأنظمة المبنية على الشفافية المرجعية هي أيضًا جيدة لأنها يمكن التنبؤ بها. إن ثبات الحالة يجعل هذه الأنظمة أسهل في الفهم والتغيير والتحسين. هذا يقلل بشكل كبير من احتمال السباقات وغيرها من القضايا multithreading.
الفكرة الرئيسية هنا هي:
لا يوجد holivar FP vs OOP
FP و OOP العمل بشكل جيد معا. كلاهما جيد ومناسب للاستخدام في النظم الحديثة. يعمل هذا النظام ، الذي يستند إلى مجموعة من مبادئ OOP و FP ، على زيادة المرونة والقدرة على الصيانة والقابلية للاختبار والبساطة والقوة. إذا قمت بإزالة واحدة لإضافة أخرى ، فسيؤدي ذلك إلى تفاقم هيكل النظام.
[1] بما أننا نستخدم آلات ذات بنية Von Neumann ، فإننا نفترض أن لديهم خلايا ذاكرة تتغير حالتها بالفعل. في آلية العودية التي وصفتها ، لن يسمح تحسين العودية الذيل الخلفي بإنشاء إطارات زجاجية جديدة وسيتم استخدام الإطار الزجاجي الأصلي. لكن هذا الانتهاك للشفافية المرجعية (عادة) مخفي عن المبرمج ولا يؤثر على أي شيء.