:: كل المقالات ::

Tue, 13 Dec 2016

البرمجة الكائنية في بيرل (الجزء الثالث) " الطريقة الحديثة"

بسم الله الرحمن الرحيم

نواصل الكلام عن البرمجة الكائنية في بيرل و هذه المرة سنستعرض النموذج الحديث او ما يعرف بـ Moose و قد تقدم الكلام عن الجانب التاريخي و النظري في المقالة الاولى . هذه المرة لن استرسل في شرح المصطلحات و المفاهيم فقد قمنا بهذا الامر في المقالتين الاولى و الثانية و مهمتنا هنا فقط استعراض طريقة الكتابة و التنبيه الى اوجه الاختلاف ان وجدت.
نبدأ بتعريف كلاس جديد باسم car بهذه الطريقة :
package Car;
use Moose;
انتهى ! هذا كلاس كامل و في النموذج الجديد Moose تقوم بتوفير الكونستركتر الافتراضي بالاضافة الى توفير الـ getters و الـ setters فلا نحتاج لكتابة اكواد خاصة لها ! حسنــــاً لنجعل من هذا الكلاس كلاسا مجردا Abstract اي انه لا يمكن انشاء اي كائن من هذا الكلاس فالغرض الرئيسي منه هو غرض تنظيمي ، و ذلك يتم باضافة هذا السطر :
use MooseX::ABC;
الان نأتي لطريقة كتابة الخصائص في النموذج الجديد :
has 'make' => (is => 'rw' , isa => 'Str');
has 'type' => (is => 'rw' , isa => 'Str');
في مثالنا قلنا ان الكلاس هذا يحتوي على خاصية باسم make "اسم الشركة المصنعة" و ان تصريح الوصول اليه rw و هي اختصار لـ read write اي يمكن الوصول الى هذا الخاصية و يمكن تغيير محتواها . في نهاية التعريف قلنا اننا نتوقع قيمة نصية لهذه الخاصية . نلاحظ ان الاعلان عن الخصائص في النموذج الجديد مفصل و واضح و افضل بكثير من النموذج القديم يكفي فقط خاصية تحديد نوع البيانات . قلنا ايضا ان Moose ستنشئ لنا ميثودات مساعدة بدون الحاجة الى كتابتها يدويا فالان يمكننا ان نصل الى قيم الخصائص هكذا ( لو على فرض ان الكلاس ليس كلاسا مجردا و يمكن فعليا انشاء كائنات منه ) :
use v5.12;
my $car = Car->new( make => 'toyota' , type =>'camry');
say $car->make(); #toyota
بل يمكننا ان نعدل قيم الخصائص ايضا فلو على فرض ان شركة نيسان قامت بشراء فئة الكامري من تويوتا فيمكننا ان ننقل الملكية هكذا:
$car->make('Nissan');
say $car->make(); #Nissan
الان لانشاء كلاس Salon يرث هذا الكلاس المجرد :
package Salon;
use Moose;
extends 'Car';
فكلمة extends هنا هي من تقوم بتحديد العلاقة بين الكلاسين بأنها وراثية . طبعا كلاس صالون سيرث كل شيء من الكلاس الاب و يمكننا ان نضيف اشياء خاصة به مثلا:
has 'options' => (is => 'rw' , isa => 'Str');
طبعا انشاء الخصائص في النموذج الجديد مفصل جدا و لو تقصينا الكلام عن امكانياته فسيطول بنا المقام . لكن هنا احببت الكلام عن الـ roles و هي شيء يشبه الـ interfaces في جافا حيث انها كلاسات مهمتها تنظيمية و يمكن استخدامها تماما مثلما تستخدم في جافا او بطرق اخرى حيث في بيرل يمكن اضافة الاكواد الخاصة بالميثودز و ليس فقط الاكتفاء باعلان اسماء الميثودز . لنأخذ مثالا لتتضح الصورة فمثلا بعض الكلاسات توفر آلية لحفظ الكائنات و استرجاعها لاحقا هذه الالية من الافضل ان تطبق على انها واجهة بدلا من علاقة التوارث . و في النموذج الجديد الامر بهذه البساطة :
package Storable;
use Moose::Role;
requires 'store';
فهنا قلنا ان Storable تتطلب ان يكون الكلاس المطبق يحتوي على ميثود باسم store. و الان عندما نعلن عن كلاس ما بأنه يطبق هذه الواجهة بالامر :
with 'Storable';
فعلينا ان نقوم بإنشاء ميثود باسم store و الا سيرجع لنا المفسر خطأ :
sub store{
#some code to store the object
};
و لو اردنا ان نستعلم عن كلاس ما في كونه يطبق واجهة معينة او لا فيمكننا ذلك من خلال الامر DOES :
say "it is storable" if $car->DOES('Storable');
بشكل عام ينصح باستخدام الـ roles بدلا من استخدام التعدد في التوارث . على كل حال لن اطيل في استعراض نموذج Moose فهناك الكثير ليقال هنا و لكن فيما تقدم استعراض لاهم المزايا التي نستخدمها بشكل متكرر .
ختاما تجدر الاشارة الى ان هناك مكتبات اخرى متوافقة مع Moose مثل Moo و Mouse و لكن هناك مكتبات اخرى تقدم نماذج كائنية خاصة بها و لها فلسفتها الخاصة ، هذا بالاضافة الى الكثير من المكتبات المساعدة التي تقدم آليات لتسهيل البرمجة الكائنية في النموذج القديم مثلا Object::Tiny تقدم ابسط اشكال بناء الكلاسات و اكثرها اختصارا :
# Define a class
package Foo;
use Object::Tiny qw{ bar baz };
1;
# Use the class
my $object = Foo->new( bar => 1 );
print "bar is " . $object->bar . "\n";
خلاصة المطلب في هذه السلسلة من المواضيع ان بيرل مختلفة عن اكثر لغات البرمجة من حيث انها تحتوي على اكثر من نموذج كائني . و قد استعرضنا النموذج القديم و بعض النماذج الجديدة من هنا قد يلحظ القارئ الكريم قوة هذه اللغة من حيث امكانية تطويعها الى حدود قصوى .
دمتم في الرضا ،