سؤال

ما مبادئ OOP، إن وجدت، لا تنطبق أو تنطبق بشكل مختلف في بيئة مكتوبة ديناميكية بدلا من بيئة مكتوبة ثابتة (على سبيل المثال Ruby VS C #)؟ هذه ليست مكالمة للحصول على نقاش ديناميكي ثابت مقابل النقاش، بل أود أن أرى ما إذا كانت هناك مبادئ مقبولة على جانبي تلك الفجوة التي تنطبق على واحد وليس الآخر، أو تنطبق بشكل مختلف. عبارات مثل "تفضيل التركيب للميراث" معروفة جيدا في أدب OOP المكتوبة بشكل ثابت. هل هم فقط قابلة للتطبيق على الجانب الديناميكي؟

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

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

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

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

class Bartender
    def initialize(bar)
       @bar = bar
    end

    def do_some_bar_stuff
        @bar.open
        @bar.tend
        @bar.close
    end
end

class Bar
    def open
        # open the doors, turn on the lights
    end
    def tend
        # tend the bar
    end
    def close
        #clean the bathrooms
    end
end

class BoringSportsBar < Bar
    def open
        # turn on Golden Tee, fire up the plasma screen
    end

    def tend
        # serve lots of Bud Light
    end
end

class NotQuiteAsBoringSportsBar < BoringSportsBar
    def open
        # turn on vintage arcade games
    end
end

class SnootyBeerSnobBar < Bar
    def open
        # replace empty kegs of expensive Belgians
    end

    def tend
        # serve lots of obscure ales, porters and IPAs from 124 different taps
    end
end

# monday night
bartender = Bartender.new(BoringSportsBar.new)
bartender.do_some_bar_stuff

# wednesday night
bartender = Bartender.new(SnootyBeerSnobBar.new)
bartender.do_some_bar_stuff

# friday night
bartender = Bartender.new(NotQuiteAsBoringSportsBar.new)
bartender.do_some_bar_stuff
هل كانت مفيدة؟

المحلول

الفرق الأساسي الذي تلمسه على ما أعتقد

  • مجموعة اللغات 1. الأساليب الفعلية التي يتم الاحتجاج بها عند مثل Object.Method1، Object.method2، يتم استدعاء Object.Method3 يمكن أن تتغير أثناء عمر الكائن.

  • مجموعة اللغات 2. الأساليب الفعلية التي يتم الاحتجاج بها عند مثال enjobs.method1، enjobs.method2، يتم استدعاء Object.Method3 لا يمكن تغييرها أثناء عمر الكائن.

تميل اللغات في المجموعة الأولى إلى الحصول على طباعة ديناميكية وعدم دعم واجهات الترجمة التي تم فحص الوقت واللغات في المجموعة 2 تميل إلى الحصول على الكتابة الثابتة ودعم واجهات Compile-Time Chcked.

أود أن أقول أن جميع مبادئ OO تنطبق على كليهما، ولكن

  • قد تكون هناك حاجة إلى بعض الترميز الإضافي (الصريح) لتنفيذ (وقت التشغيل بدلا من الترجمة بدلا من وقت الترجمة) في المجموعة 1 لتأكيد أن الكائنات الجديدة التي يتم إنشاؤها بكل الطرق المناسبة التي تسببت في تلبية عقد واجهة لا يوجد وقت ممكن فحص اتفاقية الواجهة، (إذا كنت ترغب في جعل رمز المجموعة 1 أشبه المجموعة 2)

  • قد تكون هناك حاجة إلى بعض الترميز الإضافي في المجموعة 2 إلى نموذج التغييرات في الطريقة الفعلية التي تم استدعاءها للحصول على طريقة استدعاء طريقة باستخدام إشارات الحالة الإضافية للاتصال بمشاركة Submethods، أو لتختتم الطريقة أو مجموعة من الأساليب في إشارة إلى واحدة من العديد من الكائنات المرفقة إلى الكائن الرئيسي، حيث يحتوي كل من الكائنات العديد من الأجسام على تطبيقات أسلوب مختلفة، (إذا كنت ترغب في إنشاء رمز المجموعة 2 أشبه المجموعة 1)

  • إن القيود المفروضة على التصميم في المجموعة 2 تجعلها أفضل للمشروعات الأكبر حيث يصبح سهولة الاتصال (على عكس الفهم) أكثر أهمية

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

  • جعل الكود من مجموعة واحدة من اللغات مثل الآخر مثير للاهتمام ويستحق الدراسة ولكن نقطة الاختلافات اللغوية هي حقا أن تفعل مع مدى جودة مساعدة أحجام مختلفة من الفرق (- أعتقد! :))

  • هناك اختلافات أخرى مختلفة

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


تعديل

حتى الإجابة على سؤالك الأصلي، قمت بفحص

http://c2.com/cgi/wiki؟principlesofobjectorienteddesign.

و

http://www.dofactory.com/patterns/patterns.aspx.

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

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

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

IMHO يجعل الكثير من المعنى في معظم لغات المجموعة 1 للتفكير في جميع البيانات العالمية والوظائف ككائن نوع من Singleton "التطبيق". أعلم أننا نحصل على عدم وضوح الخطوط بين البرمجة الإجرائية و OO، ولكن هذا النوع من التعليمات البرمجية مؤكدا مثل كائن "التطبيق" في الكثير من الحالات! :)

تميل بعض أنماط التصميم المحبوسة بشكل جيد للغاية مثل ITERATOR إلى إنشاء لغات المجموعة 1.

نصائح أخرى

اسمحوا لي أن أبدأ بقول ذلك، شخصيا، مبدأ OOP لا يعمل على اللغات الديناميكيا والثابتة ثابتة ليس مبدأ.

ومع ذلك، هنا مثال:

مبدأ فصل واجهة (http://objectmentor.com/resources/articles/isp.pdf.تنص على أن العملاء يجب أن يعتمدون على الواجهة الأكثر تحديدا التي تلبي احتياجاتهم. إذا كان رمز العميل يحتاج إلى استخدام طريقتين من الفئة C، يجب على C تنفيذ واجهة، وأنا، الذي يحتوي فقط على هذين الطريقتين فقط وسيستخدم العميل أنا بدلا من C. المبدأ غير ذي صلة في اللغات المكتوبة بشكل حيوي حيث لا يلزم وجود واجهات (منذ واجهات الأنواع المحددة، والأنواع ليست ضرورية بلغة حيث تكون المتغيرات أقل)

تعديل

المثال الثاني - مبدأ انعكاس التبعية (http://objectmentor.com/resources/articles/dip.pdf.). يجادل هذا المبدأ هو "استراتيجية اعتمادا على الواجهات أو الوظائف والفئات المجردة، بدلا من الوظائف والفئات الخرسانية". مرة أخرى، لا يعتمد رمز عميل اللغة المكتوبة بشكل حيوي على أي شيء - إنه يحدد فقط توقيعات الأسلوب - وبالتالي تجنب هذا المبدأ.

المثال الثالث - مبدأ استبدال Liskov (http://objectmentor.com/resources/articles/lsp.pdf.). مثال كتاب النص لهذا المبدأ هو فئة مربعة تثقيف فئة مستطيلة. وبعد ذلك، يفاجأ رمز العميل الذي يستدعي طريقة SetWidth () على متغير مستطيل عندما يتم تغيير الارتفاع أيضا لأن الكائن الفعلي هو مربع. مرة أخرى، في لغة مكتوبة ديناميكيا، فإن المتغيرات أقل من النوع، لن يتم ذكر فئة المستطيل في رمز العميل وبالتالي لن تنشأ هذه المفاجآت.

لدي عرض "جذرية" حول كل هذا: في رأيي، مدعومة من الرياضيات، لا يعمل OOP في بيئة مكتوبة قانونيا لأي مشاكل مثالية. أعرف مثيرة مثيرة لأن العلاقات المجردة المعنية تشارك. يمكن إثبات ذلك بسهولة (انظر "مشكلة التباين").

جوهر هذه المشكلة هو أن مفاهيم منظمة OOP هي وسيلة لنموذج التجريدات والقدم مع برامج العقد التي تم تسليمها عن طريق الكتابة الثابتة، ولا يمكن تنفيذ العلاقات دون كسر التغليف. ما عليك سوى تجربة أي مشغل ثنائي Covariant لمعرفة: حاول تنفيذ "أقل من" أو "إضافة" في C ++. يمكنك رمز التجريد الأساسي بسهولة ولكن لا يمكنك تطبيقه.

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

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

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

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

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

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

إذا كنت ستستخدم لغة ثابتة، فاستخدمها لصالحك.

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