لماذا الادعاء بأن الأشخاص في لغة C# لا يحصلون على برمجة موجهة للكائنات؟(مقابل موجه نحو الفصل)

StackOverflow https://stackoverflow.com/questions/52092

  •  09-06-2019
  •  | 
  •  

سؤال

هذا لفت انتباهي الليلة الماضية.

على الاحدث ألت.نت بودكاست يناقش سكوت بيلوير كيف أن لغات مثل c# وjava وآخرون تختلف عن روبي.ليسوا حقًا موجهين للكائنات بدلاً من اختيار عبارة "موجهة نحو الفصل".ويتحدثون عن هذا التمييز بعبارات غامضة للغاية دون الخوض في الكثير من التفاصيل أو مناقشة الإيجابيات والسلبيات كثيرًا.

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

تحديث:بعد قراءة بعض الإجابات أدناه، يبدو أن الناس يتفقون بشكل عام على أن الإشارة هي إلى كتابة البط.ما لست متأكدًا من أنني أفهمه حتى الآن هو الادعاء بأن هذا يغير كل شيء في النهاية كثيرًا.خاصة إذا كنت تقوم بالفعل بإجراء tdd مناسب باستخدام أداة التوصيل السائبة بلاه بلاه.هل يمكن لأحد أن يريني مثالاً لشيء رائع يمكنني فعله باستخدام روبي ولا يمكنني فعله باستخدام c# والذي يمثل مثالاً على نهج oop المختلف هذا؟

هل كانت مفيدة؟

المحلول

تُعزى تعليقات كتابة البطة هنا إلى حقيقة أن روبي وبيثون أكثر متحرك من C #.ليس لها حقًا أي علاقة بـ OO Nature.

ما (أعتقد) أن بيلوير قصدته بذلك هو أنه في روبي، كل شيء هو كائن.حتى فئة.تعريف الفئة هو مثيل للكائن.على هذا النحو، يمكنك إضافة/تغيير/إزالة السلوك إليه في وقت التشغيل.

مثال جيد آخر هو أن NULL كائن أيضًا.في روبي، كل شيء هو كائن حرفيًا.إن وجود مثل هذا OO العميق في كيانه بأكمله يسمح ببعض تقنيات البرمجة التعريفية الممتعة مثلmethod_missing.

نصائح أخرى

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

IMO، إنها في الواقع تُعرّف بشكل مفرط "الكائنات الموجهة"، لكن ما يشيرون إليه هو أن Ruby، على عكس C#، وC++، وJava، وآخرون، لا تستفيد من تعريف فصل دراسي - أنت لا تعمل إلا بشكل مباشر مع الأشياء.على العكس من ذلك، في C# على سبيل المثال، يمكنك تحديد الطبقات أنه يجب عليك بعد ذلك إنشاء مثيل إلى كائن عن طريق الكلمة الأساسية الجديدة.النقطة الأساسية هي أنه يجب عليك يعلن فئة في C# أو وصفها.بالإضافة إلى ذلك، في روبي، كل شئ - الأعداد الزوجية، على سبيل المثال - هي كائن.في المقابل، لا تزال لغة C# تحتفظ بمفهوم نوع الكائن ونوع القيمة.أعتقد أن هذا في الواقع يوضح النقطة التي يطرحونها حول C# واللغات المماثلة الأخرى - الكائن يكتب والقيمة يكتب يعني أ يكتب النظام، مما يعني أن لديك نظامًا كاملاً وصف الأنواع بدلاً من مجرد العمل مع الكائنات.

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

هناك ثلاث ركائز لـ OOP

  1. التغليف
  2. ميراث
  3. تعدد الأشكال

إذا كانت اللغة قادرة على القيام بهذه الأشياء الثلاثة فهي لغة OOP.

أنا متأكد تمامًا من أن حجة اللغة X تجعل OOP أفضل من اللغة A ستستمر إلى الأبد.

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

Static OO كما هو الحال في C# لا يحتوي على هذا النوع من التغليف.رسالة لديه لتتوافق مع طريقة أو خاصية موجودة، وإلا فإن المترجم سوف يشتكي.ومع ذلك، تدعم اللغات الديناميكية مثل Smalltalk أو Ruby أو Python OO "المعتمدة على الرسائل".

لذا، بهذا المعنى فإن لغة C# ولغات OO الأخرى المكتوبة بشكل ثابت ليست صحيحة، نظرًا لأنها تفتقر إلى التغليف "الحقيقي".

تحديث:إنها الموجة الجديدة..مما يشير إلى أن كل ما كنا نفعله حتى الآن قد انتهى..يبدو أنه يدعم قليلاً في البودكاست والكتب.ربما هذا ما سمعته.

حتى الآن كنا مهتمين بالفئات الثابتة وليس العنان قوة التنمية الموجهة للكائنات.لقد كنا نفعل "Dev القائم على الفصل". الفصول هي قوالب ثابتة/ثابتة لإنشاء كائنات.يتم إنشاء جميع كائنات الفئة على قدم المساواة.

على سبيل المثالفقط لتوضيح ما كنت أتكلم عنه...اسمح لي باستعارة مقتطف كود Ruby من تسجيل الشاشة PragProg الذي كان لي شرف المشاهدة للتو."التطوير القائم على النموذج الأولي" يطمس الخط الفاصل بين الكائنات والفئات.ليس هناك فرق.

animal = Object.new                  # create a new instance of base Object

def animal.number_of_feet=(feet)     # adding new methods to an Object instance. What?
  @number_of_feet = feet
end
def animal.number_of_feet
  @number_of_feet
end

cat = animal.clone          #inherits 'number_of_feet' behavior from animal
cat.number_of_feet = 4

felix = cat.clone           #inherits state of '4' and behavior from cat
puts felix.number_of_feet   # outputs 4

الفكرة هي أنها طريقة أقوى لوراثة الحالة والسلوك من الميراث التقليدي القائم على الطبقة.فهو يمنحك المزيد من المرونة والتحكم في بعض السيناريوهات "الخاصة" (التي لم أفهمها بعد).يسمح هذا بأشياء مثل Mix-ins (إعادة استخدام السلوك دون وراثة الفصل).

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

class Container < (rand < 0.5 ? Array : Hash)
end

يبدو أن روبي وجافا سكريبت واللواء الجديد هم من رواد هذا الأمر.أنا لا أزال خارج هذا الأمر ...القراءة ومحاولة فهم هذه الظاهرة الجديدة.يبدو أنها قوية..قوي جدا..مفيد؟أحتاج أن أفتح عيني أكثر قليلاً.أوقات مثيرة للاهتمام..هؤلاء.

لقد استمعت فقط إلى أول 6-7 دقائق من البودكاست التي أثارت سؤالك.إذا كان قصدهم هو القول بأن لغة C# ليست لغة موجهة للكائنات بحتة، فهذا صحيح بالفعل.كل شيء في C# ليس كائنًا (على الأقل العناصر الأولية ليست كذلك، على الرغم من أن الملاكمة تنشئ كائنًا يحتوي على نفس القيمة).في روبي، كل شيء هو كائن.يبدو أن دارين وبن قد تناولا جميع القواعد في مناقشتهما حول "كتابة البطة"، لذلك لن أكررها.

ما إذا كان هذا الاختلاف (كل شيء كائنًا مقابل كل شيء ليس كائنًا) ماديًا/مهمًا أم لا هو سؤال لا يمكنني الإجابة عليه بسهولة لأنني لا أملك عمقًا كافيًا في روبي لمقارنته بـ C#.أولئك منكم الذين يعرفون Smalltalk (لا أعرف، على الرغم من أنني أتمنى أن أعرف ذلك) ربما كانوا ينظرون إلى حركة Ruby ببعض التسلية لأنها كانت أول لغة OO نقية منذ 30 عامًا.

ربما كانوا يلمحون إلى الفرق بين كتابة البط والتسلسل الهرمي الطبقي؟

إذا كان يمشي مثل البطة ويصدر صوتًا مثل البطة، فقط تظاهر بأنها بطة واركلها.

في C#، جافا وما إلى ذلك.يهتم المترجم كثيرًا بما يلي:هل مسموح لك القيام بهذه العملية على هذا الكائن؟

وجوه المنحى مقابل.لذلك يمكن أن يعني التوجه نحو الطبقة ما يلي:هل تقلق اللغة بشأن الأشياء أو الفئات؟

على سبيل المثال:في Python، لتنفيذ كائن قابل للتكرار، ما عليك سوى توفير طريقة __iter__() تقوم بإرجاع كائن له طريقة مسماة next().هذا كل ما في الامر:لا يوجد تنفيذ للواجهة (لا يوجد شيء من هذا القبيل).لا يوجد تصنيف فرعي.مجرد التحدث مثل البطة / التكرار.

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

لقد كان ذلك بودكاست مجردًا بالفعل!
لكني أرى ما الذي يقصدونه، لقد انبهروا بروبي سباركل.تتيح لك Ruby القيام بأشياء لم يكن مبرمجو C وJava يفكرون فيها + تتيح لك مجموعات من هذه الأشياء تحقيق إمكانيات لم تحلم بها.إضافة أساليب جديدة إلى فئة String المضمنة التي تريدها، وتمرير كتل غير مسماة من التعليمات البرمجية للآخرين لتنفيذها، والمزج...لا يعتاد الأشخاص التقليديون على تغيير الكائنات بعيدًا عن قالب الفصل الدراسي.إنه عالم جديد تمامًا هناك بالتأكيد..

أما بالنسبة لفريق C# فلا يكفي OO ...لا تأخذه على محمل الجد..فقط اعتبرها مثل الأشياء التي تتحدث بها عندما تشعر بالذهول من الكلمات.روبي يفعل ذلك لمعظم الناس.
لو كان علي أن أوصي بلغة واحدة ليتعلمها الناس في العقد الحالي..سيكون روبي.أنا سعيد لأنني فعلت..على الرغم من أن بعض الناس قد يدعون بايثون.لكنه مثل رأيي..رجل!:د

لا أعتقد أن الأمر يتعلق على وجه التحديد بكتابة البط.على سبيل المثال، يدعم C# كتابة البطة المحدودة بالفعل - على سبيل المثال، يمكنك استخدام foreach on أي فئة تطبق MoveNext وCurrent.

يتوافق مفهوم كتابة البطة مع اللغات المكتوبة بشكل ثابت مثل Java وC#، وهو في الأساس امتداد للانعكاس.

هذه هي حالة الكتابة الثابتة مقابل الكتابة الديناميكية.كلاهما صحيح-OO، بقدر ما يوجد شيء من هذا القبيل.خارج الأوساط الأكاديمية، الأمر لا يستحق المناقشة حقًا.

يمكن كتابة رمز القمامة في أي منهما.يمكن كتابة كود عظيم في أي منهما.لا يوجد أي شيء وظيفي على الإطلاق يمكن لأحد النماذج أن يفعله ولا يستطيع الآخر القيام به.

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

على سبيل المثال، يعد التحسس الذكي لـ Java أو C# أمرًا سهلاً - يمكن لـ IDE إنتاج قائمة منسدلة من الاحتمالات بسرعة.بالنسبة لجافا سكريبت أو روبي، يصبح هذا الأمر أكثر صعوبة.

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

من المفيد أن يكون لديك فهم لكليهما في مجموعة أدوات المهارات الخاصة بك، ولكن ليس بنفس أهمية فهم الأداة التي تستخدمها بالفعل بعمق حقيقي.

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

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

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

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

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

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

ولكن هذه تفاصيل تنفيذ صغيرة - لا علاقة لها بمبدأ OO الأساسي.لم يُقال في أي مكان أن الكائنات يجب أن تكون ديناميكية أو يجب أن تكون قابلة للتغيير أثناء وقت التشغيل.تقول ويكيبيديا ذلك بشكل جيد:

قد تتضمن تقنيات البرمجة ميزات مثل إخفاء المعلومات ، وتجريد البيانات ، والتغليف ، والنموذج ، وتعدد الأشكال ، والميراث.

http://en.wikipedia.org/wiki/Object-Oriented_programming

هم يمكن أو هم ربما لا.وهذا كله ليس إلزاميا.الإلزامي هو فقط وجود الكائنات وأنه يجب أن يكون لديها طرق للتفاعل مع بعضها البعض (وإلا ستكون الكائنات عديمة الفائدة إلى حد ما إذا لم تتمكن من التفاعل مع بعضها البعض).

أنت سألت:"هل يمكن لأي شخص أن يريني مثالاً لشيء رائع يمكنني القيام به باستخدام روبي ولا يمكنني القيام به باستخدام لغة #c والذي يجسد هذا النهج المختلف لـ oop؟"

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

ربما يرجع هذا حقًا إلى ما يرى هؤلاء الأشخاص أن الآخرين يفعلونه في c# وjava بدلاً من c# وjava الذين يدعمون OOP.يمكن استخدام معظم اللغات في نماذج برمجة مختلفة.على سبيل المثال، يمكنك كتابة التعليمات البرمجية الإجرائية في C# والمخطط، ويمكنك القيام بالبرمجة ذات النمط الوظيفي في Java.يتعلق الأمر أكثر بما تحاول القيام به وما تدعمه اللغة.

سأقوم بطعنة في هذا.

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

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

نظرًا لأن حقن التبعية أسهل في اللغات المكتوبة ديناميكيًا، يشعر مطورو Ruby/Python أن لغتهم تفهم دروس OO بشكل أفضل بكثير من نظيراتها المكتوبة بشكل ثابت.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top