منظور EcmaScript للنظرية العامة لـ OOP

مرحبا يا هبر!

حتى هذا اليوم ، قمت بترجمة مقالات مثيرة للاهتمام ، حسب رأيي ، لمؤلفين يتحدثون الإنجليزية. والآن حان الوقت لكتابة شيء بنفسك. بالنسبة للمقال الأول ، اخترت موضوعًا ، وأنا متأكد من أنه سيكون مفيدًا للمطورين المبتدئين الذين يرغبون في النمو إلى "الوسط" ، لأنه سيحلل التشابه / الفرق بين جافا سكريبت ولغات البرمجة الكلاسيكية (C ++ ، C # ، Java) من حيث OOP. لذلك دعونا نبدأ!

الأحكام العامة للنموذج


إذا نظرنا إلى تعريف JavaScript على Wikipedia ، فسنرى المفهوم التالي:
تعد JavaScript (/ ˈdʒɑːvɑːˌskrɪpt /؛ abbr. JS /ˈdʒeɪ.ɛs./) لغة برمجة متعددة النماذج. يدعم وجوه المنحى ، وأساليب حتمية وظيفية. إنه تطبيق للغة ECMAScript (معيار ECMA-262).

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

النماذج التالية موجودة في EcmaScript (المشار إليها فيما يلي ES):

  • بنيوي
  • منظمة التحرير الفلسطينية
  • وظيفي
  • آمري
  • موجه نحو الجوانب (في حالات نادرة)

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

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

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

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

ما هي منظمة الطبقة الثابتة على أساس؟


أساس هذا النوع من OOP هي مفاهيم "الطبقة" و "الجوهر". الفئة هي مجموعة معممة رسمية من خصائص الكيانات التي يمكنها توليدها. أي هذه هي خطة عامة معينة لجميع الكائنات التي تم إنشاؤها بواسطة ذلك.

الخصائص هي من نوعين. الخصائص (وصف الكيان) والطرق (نشاط الكيان ، سلوكهم).

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

هنا مثال صغير على JAVA:

class Person{ String name; //  int age; //  void displayInfo(){ System.out.printf("Name: %s \tAge: %d\n", name, age); } } 

الآن قم بإنشاء مثيل للفئة:

 public class Program{ public static void main(String[] args) { Person tom; } } 

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

يوفر نموذج OOP مجموعة واسعة جدًا من إمكانيات إعادة استخدام التعليمات البرمجية ، إحدى هذه الميزات هي الوراثة .

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

ما هي عيوب هذا النهج؟

أعتقد أنه من الواضح أن:

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

ما هي منظمة النموذج الأولي على أساس؟


المفهوم الرئيسي لمؤسسة النموذج الأولي هو كائن حيوي قابل للتغيير (dmo). DMO لا يحتاج إلى فئة. هو نفسه يمكنه تخزين جميع ممتلكاته وأساليبه.

عند تعيين DMO لخاصية ، فإنه يتحقق من وجود هذه الخاصية فيها. إذا كانت هناك خاصية ، فعندها يتم تعيينها ببساطة ؛ وإذا لم تكن موجودة ، فسيتم إضافة العقار وتهيئته بالقيمة التي تم تمريرها. يمكن لـ DMOs تغيير توقيعها أثناء البرنامج عدة مرات كما يحلو لها.

هنا مثال:

 //        const Person = { name: null, age: null, sayHi() { return `Hi! My name is ${this.name}. I'm ${this.age} years old.` } } const Tom = { //-       } Tom.__proto__ = Person; 

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

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

النموذج الأولي هو كائن يعمل كنموذج أولي لكائنات أخرى أو كائن حيث يمكن لكائن آخر رسم الخصائص والأساليب إذا لزم الأمر.

يمكن أن يكون النموذج الأولي لكائن أي كائن ، علاوة على ذلك ، يمكن للكائن إعادة تعيين النموذج الأولي الخاص به أثناء البرنامج.

دعنا نعود إلى توم لدينا:

 Tom.name = 'Tom'; //    Tom.surname = 'Williams'; //    Tom.age = 28;//    Tom.sayHi();//  sayHi,      ,    ,       const tomSon = { name: 'John', age: 5, sayHi() { return this.__proto__.sayHi.call(this) + `My father is ${this.__proto__.name} ${this.surname}`; } } //,     tomSon.__proto__ = Tom; tomSon.sayHi();//  "Hi! My name is John. I'm 5 years old.My father is Tom Williams" 

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

نواصل تطوير تاريخ توم لدينا وابنه جون.

 // ,    (  ) //  ,   ,    , //      const Ben = { name: 'Ben', surname: 'Silver', age: 42, sayHi() { return `Hello! I'm ${this.name} ${this.surname}. `; } } tomSon.nativeFather = Tom; tomSon.__proto__= Ben; tomSon.sayHi(); //    (),     () //   'Hello! I'm John Silver. My father is Ben Silver' 

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

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

 Ben.hobbies = ['chess', 'badminton']; // tomSon   ,             ,      tomSon.sayAboutFathersHobies = function () { const reducer = (accumulator, current) => {`${accumulator} and ${current}`} return `My Father play ${this.hobbies.reduce(reducer)}` } tomSon.sayAboutFathersHobies(); //  'My Father play chess and badminton' 

وهذا ما يسمى نموذج تفويض النموذج الأولي أو وراثة النموذج الأولي .

كيف يتم تحديد قدرة الكيان على تنفيذ سلوك معين؟


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

ما هي مزايا النهج النموذجي؟

  • مزيد من المرونة
  • الكيانات ليس لديها خصائص لا يحتاجونها.

ما هي الجوانب السلبية؟

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

استنتاج


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

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

Source: https://habr.com/ru/post/ar468157/


All Articles