نظرة عامة موجزة عن تصميم البرمجيات كائنية التوجه

يتم إظهار ذلك من خلال تنفيذ فصول لعبة تقمص الأدوار

المقدمة

تدعم معظم لغات البرمجة الحديثة وتشجع البرمجة الشيئية (OOP). على الرغم من أننا نشهد مؤخرًا تحولًا طفيفًا بعيدًا عن هذا ، حيث يبدأ الناس في استخدام اللغات التي لا تتأثر بشدة بـ OOP (مثل Go و Rust و Elixir و Elm و Scala) ، لا يزال معظمها يحتوي على أشياء. تنطبق مبادئ التصميم التي سنحددها هنا على اللغات غير OOP أيضًا.

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

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

أنواع الكائنات

نظرًا لأننا سنقوم بنمذجة الكود الخاص بنا حول الكائنات ، فسيكون من المفيد التمييز بين مسؤولياتهم المختلفة والاختلافات.

هناك ثلاثة أنواع من الكائنات:

1. كائن الكيان

يتوافق هذا الكائن عمومًا مع كيان في العالم الحقيقي في مساحة المشكلة. لنفترض أننا نبني لعبة تقمص الأدوار (RPG) ، فسيكون كائن الكيان هو Heroالفصل البسيط لدينا :

تحتوي هذه الكائنات بشكل عام على خصائص عن نفسها (مثل healthأو mana) ويمكن تعديلها من خلال قواعد معينة.

2. كائن التحكم

كائنات التحكم (تسمى أحيانًا كائنات المدير ) هي المسؤولة عن تنسيق الكائنات الأخرى. هذه هي الأشياء التي تتحكموالاستفادة من الأشياء الأخرى. من الأمثلة الرائعة في مقارنة آر بي جي لدينا هي Fightالطبقة التي تتحكم في بطلين وتجعلهما يقاتلان.

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

3. كائن حدودي

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

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

المكافأة: قيمة الكائن

تمثل كائنات القيمة قيمة بسيطة في المجال الخاص بك. فهي غير قابلة للتغيير وليس لها هوية.

إذا أردنا دمجها في لعبتنا ، فسيكون الفصل Moneyأو Damageالفصل مناسبًا تمامًا. تسمح لنا الكائنات المذكورة بسهولة بتمييز الوظائف ذات الصلة وإيجادها وتصحيحها ، في حين أن النهج الساذج المتمثل في استخدام نوع بدائي - مصفوفة من الأعداد الصحيحة أو عدد صحيح واحد - لا يفعل ذلك.

يمكن تصنيفها على أنها فئة فرعية من Entityشاء.

مبادئ التصميم الرئيسية

مبادئ التصميم هي قواعد في تصميم البرامج أثبتت قيمتها على مر السنين. سيساعدك اتباعها بدقة على ضمان أن يكون برنامجك من الدرجة الأولى.

التجريد

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

توضح الأمثلة أعلاه التجريد - انظر إلى كيفية تنظيم Fightالفصل. طريقة استخدامه بسيطة بقدر الإمكان - تمنحه بطلين كوسيطين في إنشاء مثيل واستدعاء fight()الطريقة. لاأكثر ولا أقل.

يجب أن يتبع التجريد في الكود قاعدة أقل المفاجأة يجب ألا يفاجئ تجريدك أي شخص بسلوك / خصائص لا داعي لها وغير ذات صلة. بمعنى آخر - يجب أن تكون بديهية.

لاحظ أن Hero#take_damage()وظيفتنا لا تفعل شيئًا غير متوقع ، مثل حذف شخصيتنا عند الموت. لكن يمكننا أن نتوقع أن تقتل شخصيتنا إذا انخفضت صحته إلى ما دون الصفر.

التغليف

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

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

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

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

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

تقسيم

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

تخيل أننا أردنا دمج المزيد من ميزات RPG مثل الهواة والمخزون والمعدات وسمات الشخصية بالإضافة إلى Hero:

أفترض أنه يمكنك معرفة أن هذا الرمز أصبح فوضويًا جدًا. لدينا Heroكائن يقوم به الكثير من الاشياء في وقت واحد وهذا الرمز هو أن تصبح هشة جدا نتيجة لذلك.

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

الجواب هو تفكيك Heroالكائن إلى عدة كائنات أصغر يشتمل كل منها على بعض الوظائف.

الآن، وبعد متحللة وظائف لدينا كائن البطل في HeroAttributes، HeroInventory، HeroEquipmentو HeroBuffالأشياء، وإضافة وظائف المستقبل يكون أسهل، وأكثر مغلفة وتستخرج أفضل. يمكنك معرفة أن الكود الخاص بنا أكثر وضوحًا ووضوحًا فيما يتعلق بما يفعله.

هناك ثلاثة أنواع من علاقات التحلل:

  • جمعية- يحدد علاقة فضفاضة بين مكونين. كلا المكونين لا يعتمدان على بعضهما البعض ولكن قد يعملان معًا.

على سبيل المثال:Hero و Zoneجوه.

  • التجميع - يحدد علاقة "has-a" الضعيفة بين الكل وأجزائه. تعتبر ضعيفة ، لأن الأجزاء يمكن أن توجد بدون الكل.

مثال:HeroInventory و Item.

و HeroInventoryيمكن أن يكون الكثير Items، و Itemيمكن أن تنتمي إلى أي HeroInventory(مثل البنود التداول).

  • تكوين - علاقة "لها" قوية حيث لا يمكن أن يتواجد الكل والجزء بدون بعضهما البعض. لا يمكن مشاركة الأجزاء ، حيث يعتمد الكل على تلك الأجزاء الدقيقة.

مثال:Hero و HeroAttributes.

هذه هي سمات البطل - لا يمكنك تغيير مالكها.

تعميم

قد يكون التعميم أهم مبدأ في التصميم - فهو عملية استخراج الخصائص المشتركة والجمع بينها في مكان واحد. كل منا يعرف عن مفهوم الوظائف والوراثة الطبقية - كلاهما نوع من التعميم.

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

في المثال المذكور، قمنا المعمم لدينا شيوعا Heroو NPC ظائف الطبقات "إلى سلف مشترك يسمى Entity. هذا يتحقق دائما من خلال الميراث.

هنا، بدلا من الاضطرار لدينا NPCو Heroالطبقات تنفيذ جميع الأساليب مرتين وتنتهك مبدأ DRY، خفضنا التعقيد عن طريق تحريك وظائف المشتركة في الفئة الأساسية.

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

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

تكوين

التركيب هو مبدأ الجمع بين كائنات متعددة في كائن أكثر تعقيدًا. يقال عمليًا - إنه يخلق حالات من الكائنات ويستخدم وظائفها بدلاً من وراثتها مباشرة.

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

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

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

دعنا نوضح مشكلة محتملة تتعلق بالوظيفة الزائدة:

لقد أضفنا الحركة إلى لعبتنا للتو.

كما علمنا، بدلا من تكرار رمز كنا تعميم لوضع move_rightو move_leftظائف في Entityالصف.

حسنًا ، الآن ماذا لو أردنا إدخال حوامل في اللعبة؟

سيحتاج الحاملون أيضًا إلى التحرك إلى اليسار واليمين ولكن ليس لديهم القدرة على الهجوم. تعال إلى التفكير في الأمر - ربما لا يتمتعون بصحة جيدة!

أعرف ما هو الحل الخاص بك:

ما عليك سوى نقل moveالمنطق إلى فصل MoveableEntityأو MoveableObjectفئة بها هذه الوظيفة فقط. و Mountيمكن أن الطبقة ثم ترث ذلك.

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

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

الصيحة ، تكوين!

إخلاء المسؤولية عن التفكير النقدي

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

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

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

التماسك والاقتران وفصل الاهتمامات

تماسك

يمثل التماسك وضوح المسؤوليات داخل وحدة ما أو بعبارة أخرى - تعقيدها.

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

تريد أن تتمتع فصولك الدراسية بتماسك عالٍ. يجب أن يتحملوا مسؤولية واحدة فقط وإذا وجدت أن لديهم المزيد - فقد حان الوقت لتقسيمها.

اقتران

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

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

فصل المخاوف

فصل المخاوف (SoC) هو فكرة وجوب تقسيم نظام البرنامج إلى أجزاء لا تتداخل في الوظائف. أو كما يقول الاسم - قلق - مصطلح عام يتعلق بأي شيء يقدم حلاً لمشكلة ما - يجب فصله إلى أماكن مختلفة.

تعد صفحة الويب مثالًا جيدًا على ذلك - فهي تحتوي على طبقاتها الثلاث (المعلومات والعرض التقديمي والسلوك) مقسمة إلى ثلاثة أماكن (HTML و CSS و JavaScript على التوالي).

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

سدد دينك

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

تضمن هذه المبادئ أن نظامنا أكثر:

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

ملخص

بدأنا بتقديم بعض أنواع الكائنات الأساسية عالية المستوى (الكيان والحدود والتحكم).

ثم تعلمنا المبادئ الأساسية في هيكلة الأشياء المذكورة (التجريد والتعميم والتكوين والتحليل والتغليف).

للمتابعة ، قدمنا ​​مقياسين لجودة البرامج (الاقتران والتماسك) وتعرّفنا على فوائد تطبيق المبادئ المذكورة.

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

قراءات إضافية

أنماط التصميم: عناصر البرمجيات الكائنية القابلة لإعادة الاستخدام - يمكن القول إنها الكتاب الأكثر تأثيرًا في هذا المجال. مؤرخة قليلاً في أمثلةها (C ++ 98) لكن الأنماط والأفكار تظل ملائمة للغاية.

تزايد البرامج الموجهة للكائنات الموجهة بالاختبارات - كتاب رائع يوضح كيفية تطبيق المبادئ الموضحة في هذه المقالة (والمزيد) عمليًا من خلال العمل من خلال مشروع.

تصميم برامج فعال - مدونة من الدرجة الأولى تحتوي على أكثر بكثير من مجرد أفكار للتصميم.

تخصص تصميم البرمجيات والهندسة المعمارية - سلسلة رائعة من 4 دورات فيديو تعلمك التصميم الفعال من خلال تطبيقه في مشروع يمتد على جميع الدورات الأربع.

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