design-patterns - هندسة - نماذج تطوير البرمجيات pdf




هل تستبدل البرمجة الوظيفية أنماط تصميم GoF؟ (16)

منذ أن بدأت في تعلم F # و OCaml في العام الماضي ، قرأت عددًا كبيرًا من المقالات التي تصر على أن أنماط التصميم (خاصة في Java) هي حلول للميزات المفقودة في اللغات الضرورية. إحدى المقالات التي وجدتها تجعل من المطالبة قوية إلى حد ما :

لقد قرأ معظم الأشخاص الذين قابلتهم كتاب الأنماط التصميمية بواسطة عصابة الأربعة. سوف يخبرك أي مبرمج يحترم نفسه أن الكتاب هو ملحن لغة وأنماط تنطبق على هندسة البرمجيات بشكل عام ، بغض النظر عن اللغة التي تستخدمها. هذا هو ادعاء نبيل. للأسف ، بعيدًا عن الحقيقة.

اللغات الوظيفية معبرة للغاية. في لغة وظيفية ، لا يحتاج المرء إلى أنماط تصميم لأن اللغة على الأرجح عالية المستوى ، ينتهي بك الأمر في البرمجة في المفاهيم التي تقضي على أنماط التصميم كلها.

السمات الرئيسية للبرمجة الوظيفية تتضمن وظائف كقيم من الدرجة الأولى ، كاري ، قيم ثابتة ، إلخ. لا يبدو لي أن أنماط تصميم OO تقترب من أي من هذه الميزات.

بالإضافة إلى ذلك ، في اللغات الوظيفية التي تدعم OOP (مثل F # و OCaml) ، يبدو واضحًا لي أن المبرمجين الذين يستخدمون هذه اللغات سيستخدمون نفس أنماط التصميم المتوفرة لكل لغة OOP أخرى. في الواقع ، أنا الآن استخدم F # و OCaml كل يوم ، ولا توجد اختلافات مدهشة بين الأنماط التي استخدمها في هذه اللغات مقابل الأنماط التي استخدمها عند الكتابة في Java.

هل هناك أي حقيقة في الادعاء بأن البرمجة الوظيفية تلغي الحاجة لأنماط تصميم OOP؟ إذا كان الأمر كذلك ، فهل يمكنك نشر أو ربط مثال على نمط تصميم OOP نموذجي ومكافئه الوظيفي؟


هل هناك أي حقيقة في الادعاء بأن البرمجة الوظيفية تلغي الحاجة لأنماط تصميم OOP؟

البرمجة الوظيفية ليست هي نفسها البرمجة الشيئية. لا تنطبق أنماط التصميم الموجهة للكائنات على البرمجة الوظيفية. بدلاً من ذلك ، لديك أنماط تصميم برمجة وظيفية.

بالنسبة إلى البرمجة الوظيفية ، لن تقرأ كتب نمط تصميم OO ، ستقرأ الكتب الأخرى حول أنماط تصميم FP.

اللغة اللاأدرية

ليس تماما. اللغة اللاأدرية فيما يتعلق بلغات OO. لا تنطبق أنماط التصميم على اللغات الإجرائية على الإطلاق. أنها بالكاد منطقية في سياق تصميم قاعدة البيانات العلائقية. لا تنطبق عند تصميم جدول بيانات.

نمط تصميم نموذج OOP ومكافئته الوظيفية؟

ما ورد أعلاه لا ينبغي أن توجد. هذا يشبه طلب جزء من الشفرة الإجرائية المعاد كتابتها كرمز OO. Ummm ... إذا قمت بترجمة Fortran الأصلي (أو C) إلى Java ، فأنا لم أفعل أي شيء أكثر من ترجمته. إذا أعدت كتابته بالكامل في نموذج OO ، فلن يبدو بعد الآن أي شيء مثل Fortran أو C الأصلي - لن يكون من الممكن التعرف عليه.

ليس هناك تخطيط بسيط من OO Design إلى Designal Design. إنها طرق مختلفة جدًا للنظر إلى المشكلة.

تحتوي البرمجة الوظيفية (مثل جميع أنماط البرمجة) على أنماط تصميم. قواعد البيانات العلائقية لديها أنماط التصميم ، OO لديها أنماط التصميم ، البرمجة الإجرائية لديها أنماط التصميم. كل شيء لديه أنماط التصميم ، وحتى هندسة المباني.

أنماط التصميم - كمفهوم - هي طريقة بناء خالدة ، بغض النظر عن التكنولوجيا أو مجال المشكلة. ومع ذلك ، فإن أنماط التصميم المحددة تنطبق على مجالات وتكنولوجيات المشكلات المحددة.

كل من يفكر في ما يفعله سيكشف عن أنماط التصميم.


أرغب في توصيل عدد من الأوراق الممتازة لكن الكثيفة إلى حدٍ ما بواسطة جيريمي غيبونز: "أنماط التصميم مثل البرامج عالية المستوى من نوع البيانات العامة" و "جوهر نمط التكرار" (كلاهما متاح هنا: http://www.comlab.ox.ac.uk/jeremy.gibbons/publications/ ).

يصف كلاهما كيف أن التركيبات الوظيفية الاصطلاحية تغطي التضاريس التي تغطيها أنماط تصميم محددة في إعدادات (وجوه المنحى) الأخرى.


أعتقد أن اثنين فقط من تصميم أنماط GoF مصممة لتقديم منطق البرمجة الوظيفية إلى لغة OO الطبيعية. أفكر في الاستراتيجية والقيادة. يمكن تعديل بعض أنماط تصميم GoF الأخرى بواسطة البرمجة الوظيفية لتبسيط التصميم والحفاظ على الغرض.


أعتقد أن كل نموذج يخدم غرضًا مختلفًا وبالتالي لا يمكن مقارنته بهذه الطريقة.

لم أسمع أن أنماط تصميم GoF قابلة للتطبيق على كل لغة. لقد سمعت أنها قابلة للتطبيق على جميع لغات OOP . إذا كنت تستخدم برمجة وظيفية ، فإن مجال المشاكل التي تحلها يختلف عن لغات OO.

لن أستخدم لغة وظيفية لكتابة واجهة مستخدم ولكن إحدى لغات OO مثل C # أو Java تجعل هذه المهمة أسهل. إذا كنت أكتب لغة وظيفية ، فلن أفكر في استخدام OO Design Patterns.


أود أن أقول أنه عندما يكون لديك لغة مثل Lisp مع دعمها لوحدات الماكرو ، فيمكنك بناء تجريدات خاصة بمجال معين ، تجريدات ، والتي غالباً ما تكون أفضل بكثير من حلول المصطلحات العامة.


الأنماط هي طرق لحل مشكلات مشابهة تتم رؤيتها مرارًا وتكرارًا ، ثم يتم وصفها وتوثيقها. إذن ، لا ، FP لن تحل محل الأنماط ؛ ومع ذلك ، قد تقوم FP بإنشاء أنماط جديدة ، وجعل بعض أنماط "أفضل الممارسات" الحالية "بالية".


تتعامل أنماط OOP و GoF مع الدول. تقوم OOP بعمل نماذج للاحتفاظ بقاعدة الرمز أقرب ما يمكن إلى متطلبات الواقع. أنماط تصميم GoF هي أنماط تم تحديدها لحل مشكلات العالم الحقيقي. يتعاملون مع مشكلة الدولة بطريقة دلالية.

كما هو الحال في البرمجة الوظيفية الحقيقية لا توجد حالة ، فإنه لا معنى لتطبيق أنماط GoF. لا توجد أنماط تصميم وظيفية بنفس الطريقة هناك أنماط تصميم GoF. كل نمط تصميم وظيفي يعد أمرًا واقعيًا على النقيض من الواقع ، حيث أن الوظائف عبارة عن بنيات رياضية وليس حقيقة.

تفتقر الدوال إلى مفهوم الوقت حيث إنها دائمًا تعيد نفس القيمة مهما كان الوقت الحالي ما لم يكن الوقت جزءًا من معلمات الدوال مما يجعل من الصعب حقًا إعادة برمجة "الطلبات المستقبلية". مزيج من هذه المفردات المختلطة تجعل اللغات ليست لغات برمجة فعلية.

اللغات الوظيفية ترتفع فقط بسبب شيء واحد: القيود الطبيعية الحالية للفيزياء. تقتصر معالجات اليوم على سرعة معالجة الإرشادات وفقًا للقوانين الفيزيائية. ترى ركودا في تردد على مدار الساعة ولكن التوسع في النوى المعالجة. ولهذا السبب يصبح التوازي بين التعليمات أكثر أهمية لزيادة سرعة التطبيقات الحديثة. بما أن البرمجة الوظيفية بالتعريف ليس لها أي حالة ، وبالتالي لا يوجد لها أي آثار جانبية ، فمن الآمن معالجة الوظائف بأمان في نفس الوقت.

أنماط GoF ليست قديمة. فهي على الأقل ضرورية لنموذج متطلبات العالم الحقيقي. ولكن إذا كنت تستخدم لغة برمجة وظيفية ، فعليك تحويلها إلى مرادفاتها الهجينة. أخيرا ليس لديك فرصة لجعل البرامج الوظيفية فقط إذا كنت تستخدم المثابرة. بالنسبة للعناصر الهجينة في برنامجك ، تظل هناك ضرورة لاستخدام أنماط GoF. أي عنصر آخر هو وظيفية بحتة ليس هناك ضرورة لاستخدام أنماط GoF لأنه لا يوجد دولة.

لأن نمط GoF ليس ضروريًا للبرمجة الوظيفية الحقيقية التي لا تعني أنه لا يجب تطبيق مبادئ SOLID. مبادئ SOLID هي أبعد من أي نموذج لغوي.


تدوّن مقالة المدوّنة التي نقلتها عن مطالبتها قليلاً. FP لا يلغي الحاجة إلى أنماط التصميم. لم يتم استخدام مصطلح "أنماط التصميم" على نطاق واسع لوصف الشيء نفسه بلغات FP. لكنهم موجودون. تحتوي اللغات الوظيفية على الكثير من قواعد أفضل الممارسات في النموذج "عند مواجهة المشكلة X ، استخدام التعليمات البرمجية التي تشبه Y" ، وهو نمط التصميم بشكل أساسي.

ومع ذلك ، فمن الصحيح أن معظم أنماط التصميم الخاصة بـ OOP لا علاقة لها إلى حد كبير باللغات الوظيفية.

لا أعتقد أنه يجب أن يكون مثيراً للجدل بشكل خاص القول بأن أنماط التصميم بشكل عام موجودة فقط لتصحيح أوجه القصور في اللغة. وإذا تمكنت لغة أخرى من حل نفس المشكلة بطريقة تافهة ، فلن تحتاج اللغة الأخرى إلى نمط تصميم لها. قد لا يدرك مستخدمو تلك اللغة أن المشكلة موجودة ، لأنها ليست مشكلة في تلك اللغة.

إليكم ما ستقوله عصابة الأربعة حول هذه القضية:

اختيار لغة البرمجة مهم لأنه يؤثر على وجهة نظر المرء. تفترض أنماطنا Smalltalk / C ++ - ميزات لغة المستوى ، ويحدد هذا الاختيار ما يمكن وما لا يمكن تنفيذه بسهولة. إذا افترضنا لغات إجرائية ، فقد نكون قد أدرجنا أنماط تصميم تسمى "الوراثة" و "التغليف" و "تعدد الأشكال". وبالمثل ، يتم دعم بعض أنماطنا مباشرة من خلال اللغات الأقل شيوعًا. لدى CLOS طرق متعددة ، على سبيل المثال ، مما يقلل من الحاجة إلى نمط مثل الزائر. في الواقع ، هناك اختلافات كافية بين Smalltalk و C ++ ليعني أنه يمكن التعبير عن بعض الأنماط بسهولة أكبر في لغة واحدة أكثر من الأخرى. (انظر Iterator على سبيل المثال.)

(ما ورد أعلاه عبارة عن اقتباس من كتاب مقدمة لنماذج التصميم ، الصفحة 4 ، الفقرة 3)

السمات الرئيسية للبرمجة الوظيفية تتضمن وظائف كقيم من الدرجة الأولى ، كاري ، قيم ثابتة ، إلخ. لا يبدو لي أن أنماط تصميم OO تقترب من أي من هذه الميزات.

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

ﻟذا ، ﻧﻌم ، ﯾﺗم ﺗﺻﻧﯾف اﻟﻌدﯾد ﻣن أﻧﻣﺎط ﺗﺻﻣﯾم GoF ﻓﻲ ﻟﻐﺎت FP ، ﻷن ﺑداﺋل أﮐﺛر ﻗوة وأﺳﮭل ﺗوﺟد.

ولكن بالطبع لا تزال هناك أنماط تصميم لا تحلها لغات FP. ما هو ما يعادل FP من المفرد؟ (تجاهل للحظة واحدة أن singletons عموما نمط رهيب لاستخدام)

ويعمل بالطريقتين أيضًا. كما قلت ، فإن FP لديها أنماط تصميمها أيضًا ، فالناس لا يفكرون بها عادةً.

ولكن ربما تكون قد مررت عبر monads. ما هي ، إن لم يكن نمط تصميم "للتعامل مع الدولة العالمية"؟ هذه مشكلة بسيطة جدًا في لغات OOP التي لا يوجد بها نمط تصميم مكافئ هناك.

لا نحتاج إلى نمط تصميم لـ "زيادة متغير ثابت" ، أو "قراءة من ذلك المقبس" ، لأنه فقط ما تفعله .

في اللغات الوظيفية (الصرفة) ، فإن الآثار الجانبية والحالة القابلة للتغيير تكون مستحيلة ، إلا إذا عملت حولها مع "نمط التصميم" monad أو أي من الطرق الأخرى للسماح لنفس الشيء.

بالإضافة إلى ذلك ، في اللغات الوظيفية التي تدعم OOP (مثل F # و OCaml) ، يبدو واضحًا لي أن المبرمجين الذين يستخدمون هذه اللغات سيستخدمون نفس أنماط التصميم المتوفرة لكل لغة OOP أخرى. في الواقع ، أنا الآن استخدم F # و OCaml كل يوم ، ولا توجد اختلافات مدهشة بين الأنماط التي استخدمها في هذه اللغات مقابل الأنماط التي استخدمها عند الكتابة في Java.

ربما لأنك لا تزال تفكر بشكل حتم؟ الكثير من الناس ، بعد التعامل مع اللغات الحتمية طوال حياتهم ، يجدون صعوبة في التخلي عن هذه العادة عندما يحاولون لغة وظيفية. (لقد رأيت بعض المحاولات المضحكة جدا في F # ، حيث كانت كل وظيفة حرفيا مجرد سلسلة من عبارات 'let' ، بشكل أساسي كما لو كنت أخذت برنامج C ، واستبدلت كل الفواصل المنقوطة بـ 'let'. :))

ولكن هناك احتمالية أخرى تتمثل في أنك لم تدرك أنك تحل المشكلات بطريقة تافهة والتي تتطلب أنماط تصميم بلغة OOP.

عند استخدام الكاري ، أو تمرير وظيفة كحجة إلى أخرى ، توقف عن التفكير في كيفية القيام بذلك بلغة OOP.

هل هناك أي حقيقة في الادعاء بأن البرمجة الوظيفية تلغي الحاجة لأنماط تصميم OOP؟

نعم. :) عندما تعمل بلغة FP ، فإنك لم تعد بحاجة إلى أنماط التصميم الخاصة بـ OOP. ولكنك لا تزال بحاجة إلى بعض أنماط التصميم العامة ، مثل MVC أو أشياء أخرى غير OOP ، وتحتاج إلى اثنين من "أنماط التصميم" الخاصة بـ FP بدلاً من ذلك. كل اللغات لها عيوبها ، وأنماط التصميم عادة ما تكون طريقة عملنا حولها.

على أي حال ، قد تجد أنه من المفيد أن تجرب يدك على لغات FP "الأنظف" ، مثل ML (المفضلة الشخصية ، على الأقل لأغراض التعلم) ، أو Haskell ، حيث ليس لديك عكاز OOP للتراجع عندما تكون واجهت مع شيء جديد.

كما كان متوقعًا ، عارض عدد قليل من الأشخاص تعريفي لأنماط التصميم على أنها "ترقيع أوجه القصور في لغة ما" ، لذلك هنا مبروري: كما سبق ذكره ، فإن معظم أنماط التصميم خاصة بنموذج برمجة واحد ، أو حتى لغة محددة واحدة في بعض الأحيان. في كثير من الأحيان ، يحلون مشاكل موجودة فقط في هذا النموذج (انظر Monads for FP ، أو مصانع مجردة ل OOP). لماذا لا يوجد نمط مصنع مجردة في FP؟ لأن المشكلة التي تحاول حلها غير موجودة هناك. لذا ، إذا كانت هناك مشكلة في لغات OOP ، والتي لا توجد في لغات FP ، فمن الواضح أن هذا هو عيب في لغات OOP. يمكن حل المشكلة ، ولكن لغتك لا تفعل ذلك ، ولكنها تتطلب مجموعة من التعليمات البرمجية الأساسية منك للتغلب عليها. من الناحية المثالية ، نود أن تجعل لغة البرمجة الخاصة بنا بشكل سحري كل المشاكل تختفي. أي مشكلة لا تزال هناك من حيث المبدأ وجود نقص في اللغة. ؛)


عندما تحاول النظر إلى هذا على مستوى "أنماط التصميم" (بشكل عام) و "FP مقابل OOP" ، فإن الإجابات التي ستجدها ستكون غامضة في أفضل الأحوال.

انتقل مستوى أعمق على كلا المحورين ، مع ذلك ، والنظر في أنماط تصميم محددة وخصائص لغة محددة وتصبح الأمور أكثر وضوحا.

لذلك ، على سبيل المثال ، بعض الأنماط المحددة ، مثل الزائر والاستراتيجية والقيادة والمراقب ، تتغير أو تختفي بالتأكيد عند استخدام لغة مع أنواع البيانات الجبرية ومطابقة الأنماط والإغلاقات ووظائف الدرجة الأولى وما إلى ذلك. لا تزال بعض الأنماط الأخرى من كتاب GoF على الرغم من ذلك.

بشكل عام ، أود أن أقول أنه مع مرور الوقت ، يتم التخلص من الأنماط المحددة من خلال ميزات اللغة الجديدة (أو التي ترتفع في شعبية فقط). هذا هو المسار الطبيعي لتصميم اللغة. عندما تصبح اللغات أكثر ارتفاعًا ، فإن التجريدات التي لم يكن من الممكن استخدامها في السابق إلا في كتاب باستخدام الأمثلة أصبحت الآن تطبيقات لميزة أو مكتبة لغوية معينة.

(جانبا: ها هي مدونة أخبرتها مؤخرًا ، ولديها روابط أخرى لمزيد من النقاش حول أنماط FP والتصميم).


في كتاب 2013 الجديد المسمى "أنماط البرمجة الوظيفية - في سكالا و Clojure" المؤلف مايكل . يقوم Linn بعمل لائق يقارن ويوفر بدائل في كثير من الحالات لأنماط GoF ويناقش أيضًا الأنماط الوظيفية الأحدث مثل 'recursion tail' ، 'memoization' ، 'تسلسل كسول' ، إلخ.

هذا الكتاب متاح على Amazon. لقد وجدت أنها مفيدة للغاية ومشجعة عندما تأتي من خلفية OO لعقدين من الزمن.


كما قال الآخرون ، هناك أنماط محددة للبرمجة الوظيفية. أعتقد أن مسألة التخلص من أنماط التصميم ليست مسألة تحويل وظيفية إلى حد ما ، ولكنها مسألة تتعلق بخصائص اللغة .

ألق نظرة على كيفية إلغاء Scala لـ "نمط المفرد": يمكنك ببساطة تعريف كائن بدلاً من فصل دراسي. ميزة أخرى ، مطابقة النمط ، تساعد على تجنب التكدس في نمط الزائر. شاهد المقارنة هنا: http://andymaleh.blogspot.com/2008/04/scalas-pattern-matching-visitor-pattern.html

و Scala ، مثل F # ، هو عبارة عن مزيج من OO-functional. لا أعرف عن F # ولكن ربما لديها هذا النوع من الميزات.

توجد الإغلاقات في اللغة الوظيفية ، ولكن لا يجب أن تقتصر عليها. انهم يساعدون مع نمط المفوض.

واحد أكثر من الملاحظة. هذه القطعة من التعليمات البرمجية تطبق نمطًا: إنه كلاسيكي جدًا وعصري جدًا لدرجة أننا لا نفكر فيه عادة على أنه "نمط" ، ولكنه بالتأكيد:

for(int i = 0; i < myList.size(); i++) { doWhatever(myList.get(i)); }

اعتمدت اللغات القهرية مثل Java و C # ما هو في الأساس بناء وظيفي للتعامل مع هذا: "foreach".


لا يمكنك إجراء هذه المناقشة بدون إظهار أنظمة الكتابة.

السمات الرئيسية للبرمجة الوظيفية تتضمن وظائف كقيم من الدرجة الأولى ، كاري ، قيم ثابتة ، إلخ. لا يبدو لي أن أنماط تصميم OO تقترب من أي من هذه الميزات.

هذا لأن هذه الميزات لا تعالج نفس المشكلات التي لا يعمل بها OOP ... فهي بدائل للبرمجة الضرورية. تكمن الإجابة عن FP لـ OOP في أنظمة ML و Haskell ... على وجه التحديد ، أنواع sum ، أنواع البيانات المجردة ، وحدات ML ، Types ، Haskell.

ولكن بالطبع لا تزال هناك أنماط تصميم لا تحلها لغات FP. ما هو ما يعادل FP من المفرد؟ (تجاهل للحظة واحدة أن singletons عموما نمط رهيب لاستخدام)

أول شيء تفعله typeclasses هو القضاء على الحاجة إلى المفردات.

يمكنك الاطلاع على قائمة 23 والقضاء على المزيد ، ولكن ليس لدي الوقت الآن.



وحتى حلول OO Design Pattern هي لغة معينة. أنماط التصميم هي حلول للمشاكل الشائعة التي لا تحلها لغتك البرمجية. في Java ، يحل نمط Singleton مشكلة واحدة (شيء مبسط). في Scala ، لديك بناء مستوى أعلى يسمى Object بالإضافة إلى Class. انها استنساخ بكسله وهناك واحد فقط. ليس عليك استخدام نمط Singleton للحصول على Singleton. انها جزء من اللغة.


يلمح عرض نورفيغ إلى تحليل قام به جميع أنماط GoF ، ويقولون أن 16 من 23 نموذجًا كان لها تطبيقات أبسط في اللغات الوظيفية ، أو كانت ببساطة جزءًا من اللغة. ومن المفترض أن سبعة منها على الأقل كانت (أ) معقدًا أو ب) غير موجودة في اللغة. لسوء الحظ بالنسبة لنا ، لم يتم تعدادهم!

أعتقد أنه من الواضح أن معظم الأنماط "الإبداعية" أو "الهيكلية" في GoF هي مجرد حيل للحصول على أنظمة الكتابة البدائية في Java أو C ++ للقيام بما تريد. لكن بقية تستحق النظر بغض النظر عن اللغة التي قمت ببرمجة في.

قد يكون واحد النموذج الأولي ؛ في حين أنها فكرة أساسية لجافا سكريبت ، فإنه يجب تنفيذها من الصفر في اللغات الأخرى.

أحد الأنماط المفضلة لدي هو نمط Null Object: يمثل غياب شيء ما كشيء يقوم بنوع مناسب من لا شيء. قد يكون هذا أسهل في التصميم بلغة وظيفية. ومع ذلك ، فإن الإنجاز الحقيقي هو التحول في المنظور.






functional-programming