تعلّم البرمجة بلغة كوتلن (24): الباني Constructor

تعلّم البرمجة بلغة كوتلن (24): الباني Constructor
أستمع الى المقال

تعرّفنا في الدرس السابق، على كيفية إنشاء صنف Class بسيط. وتعرّفنا أيضًا، على بعض أعضاء الصنف Class Members، مثل: الخاصيّات Properties، ودوال الأصناف Member Functions. في هذا الدرس سنتعرف على عضو صنف Class Member مهم جدًا، ألا وهو: الباني Constructor.

ما هو الباني Constructor:

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

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

كتابة الباني صراحةً:

للتوضيح أكثر، لنعيد كتابة الصنف Mobile، كالتالي:

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

وهذا ما يخبرنا به برنامج IntelliJ IDEA. فعند وضع مؤشر الفأرة على الأقواس التي تُمثل الباني أو كلمة constructor، ستظهر نافذة تطلب منا حذف الباني ﻷن أقواسه فارغة وليس بها بيانات، كما يظهر في الصورة التالية:

استدعاء الباني Constructor Call:

عند التخلص من كل ما هو ليس ضروري، ستكون أبسط صورة للصنف الذي لا يملك أية بيانات، كالتالي:

class Mobile

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

val m = Mobile()

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

الباني الأساسي Primary constructor:

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

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

أو يمكننا الاستفادة من الباني واستقبال قيم الخاصيّات بوضع معاملات داخل أقواسه، ومن ثم تمرير قيمها كـ Arguments عند إنشاء كائن من الصنف. تمامًا مثلما نفعل عند استدعاء دالة لديها معاملات.

معاملات الباني:

للتوضيح أكثر يمكننا إعادة كتابة الصنف Mobile، كالتالي:

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

داخل الأقواس المعقوفة للصنف، وضعنا الخاصيتين وأسندنا لهما القيم التي تُمثلها المعاملات بين قوسي الباني. نلاحظ أيضًا، أننا غيرناهما من var إلى val، لأننا لا نحتاج تغيير قيمتها كالمرة السابقة باستخدام النقطة ( . ). ثم استخدمنا الخاصيتين في دالة call داخل الصنف.

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

تمامًا كالسابق، ستأخذ دالة call قيم الخاصيتين حسب قيم معاملات الباني. وسيتم طباعة كل جملة حسب بيانات كل كائن “جوّال” على حدة، كما يظهر في الصورة التالية:

ولكن هذه المرة، تبدو الشفرة مرتبة أكثر وأقل من الشفرة السابقة. 

وضع الخاصيّات داخل أقواس الباني:

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

سنعدّل على شفرة الصنف Mobile، كالتالي:

عند استدعاء باني الصنف Mobile هذه المرة أيضًا يجب أن نضع قيم لمعاملاته، والتي هي في الوقت ذاته خاصيّات الصنف. في شفرة Mobile قبل أن نعدلها، كان الباني يستقبل قيم المعاملات ثم يسندها للخاصيّات التي تم إعلانها داخل أقواس الصنف. أما الآن، سيقوم الباني بنفس العمل، فقط هذه المرة الخاصيّات توجد بين أقواسه. وهذا ﻷن كوتلن وفرت هذه الطريقة المختصرة، لمزيد من التخلص من الشفرات المكررة.

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

كلمتي val و var في الباني:

ليتم التعامل مع معاملات الباني كخاصيّات، يجب أن نكتب إحدى هاتين الكلمتين المفتاحيتين. كما أن دالة call داخل الصنف، لا تستطيع الوصول إلى قيم معاملات الباني، ولكن تستطيع الوصول إلى قيم الخاصيّات داخل الصنف. 

فبمجرد وضع val أو var قبل اسم معامل الباني، يصبح خاصيّة أيضًا. لذا في هذه الحالة تستطيع دالة call الوصول إلى القيمة التي يستقبلها المعامل، ﻷن الباني يسندها إلى خاصيّة بنفس الاسم، قبل حفظ الصنف في ذاكرة الحاسب.

المعاملات الافتراضية والمسماة:

يمكننا وضع قيم افتراضية لمعاملات الباني التي نعلنها كخاصيّات، باتباع نفس الطريقة التي استخدمناها في الدرس السابق، كالتالي:

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

val m1 = Mobile(“Samsung”, “s9 plus”)

أو

val m1 = Mobile(“Samsung”)

أو

val m1 = Mobile()

ويمكن أيضًا عند الاستدعاء، تسمية المعاملات مباشرة، أو ارسال القيم بالترتيب ونترك لكوتلن خيار إسناد القيم للمعاملات، كالتالي:

val m1 = Mobile(company = “Samsung”, model = “s9 plus”)

أو

val m1 = Mobile(“Samsung”, “s9 plus”)

إنشاء الصنف في سطر واحد فقط:

إذا أردنا من الصنف Mobile تمثيل بيانات الكائن “جوّال” فقط ولم نرد منه أن يطبع أي شئ، فيمكننا حذف دالة call من الصنف. بعد حذف الدالة، ستصبح الأقواس المعقوفة فارغة بدون شفرة. لذا يمكننا حذفها الآن. ليكون الشكل النهائي للصنف الذي يملك خاصيتين فقط، كالتالي:

هكذا نكون قد حولنا الصنف Mobile، إلى صنف يُمثل البيانات فقط ولا يملك أية وظيفة. أو فيما يعرف بـ صنف بيانات Data Class، والذي سنتحدث عنه بتفصيل أكبر في القسم القادم من هذه السلسلة.

كتلة التهيئة Initializer Block:

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

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

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

عند إنشاء كائن جديد من الصنف Initializer في الدالة ()main:

سيتم طباعة الجملة الموجودة بين قوسي دالة ()println:

Hello from initializer block

هذا ﻷن ما يوجد بداخل init تم تنفيذه مباشرةً أثناء بناء الكائن من الصنف Initializer.

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

هل أعجبك المحتوى وتريد المزيد منه يصل إلى صندوق بريدك الإلكتروني بشكلٍ دوري؟
انضم إلى قائمة من يقدّرون محتوى إكسڤار واشترك بنشرتنا البريدية.