المساعد الشخصي الرقمي

مشاهدة النسخة كاملة : شرح الأكشن سكربت 3 الجزء الثاني البرمجة الكائنية (oop)


abohmam
06-03-2015, 08:16 PM
بسم الله الرحمن الرحيم

الحمدلله والصلاة والسلام على رسول الله وعلى آله وصحبه أجمعين

السلام عليكم ورحمة الله وبركاته

الجزء الثاني: البرمجة الكائنية (OOP)

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

لمتابعة الجزء الأول اضغظ هنا (http://www.abc4web.net/vb/showthread.php?t=31282)

في هذا الجزء ان شاء الله سوف نتكلم عن البرمجة الكائنية

OOP: تعني Oriented Object Programming
بالفرنسية Programmation Orienté Objet


http://4.bp.blogspot.com/-C4mrbHdLJ6I/VA-oiie5EjI/AAAAAAAAAQQ/UoljKIYIeFY/s1600/oop.jpg
_______________________

البرمجة الكائنية يمكن اعتبارها كطريقة جديدة للتفكير و انشاء برنامج
الكثير يعتبرها كنموذج للبرمجة .

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

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

______________

المقدمة:

سنة 1967 ظهرت أول لغة برمجية من هذا النوع تحت اسم simula-67 (http://ar.wikipedia.org/wiki/%D8%B3%D9%8A%D9%85%D9%88%D9%84%D8%A7_%28%D9%84%D8% BA%D8%A9_%D8%A8%D8%B1%D9%85%D8%AC%D8%A9%29)
simula هي اختصار ل simulation أي المحاكاة
و هذا يعني محاكاة أي موقف للبرمجة في ذلك الوقت مثل برامج التسيير و المحاسبة ..الخ


و هنا ظهرمصطلح الكائنات, الكلاس , الاحداث و ايضا جامع القمامة (garbage collector)
أما مصطلح Oriented Object فلقد أطلقه ألان كاي (Alan kay (http://ar.wikipedia.org/wiki/%D8%A3%D9%84%D8%A7%D9%86_%D9%83%D8%A7%D9%8A)) مهندس عند Xerox
الذي قام يتوسيع ما استعمل في simula-67 و قام بتطوير لغة smalltalk (http://ar.wikipedia.org/wiki/%D8%B3%D9%85%D9%88%D9%84_%D8%AA%D9%88%D9%83)
و هو يعتبر نقطة الانطلاق الرسمي في برمجة الكائنات.

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

____________________________________

مفاهيم:

الكلاسات Classes:

سبق و تكلمنا عن المتغيرات و انواعها في الدرس الثاني من الجزء الأول (http://www.abc4web.net/vb/showpost.php?p=278742&postcount=2)
و قلنا هناك متغيرات بسيطة و معقدة
سنجد نفسنا دائما نستعمل نفس الانواع
String, int, Number, Array..الخ


لكن ماذا لو أردنا صنع متغيرات خاصة بنا؟ تملك خصائص و وظائف معينة
في الحقيقة المتغيرات المعقدة هي الكلاسات
و هي مزيج من المتغيرات و التي تدعى attributes
و الدوال التي تدعى methods


الكلاس هي العجينة الاساسية التي بها نقوم بانشاء الكائنات
بعد صنع الكلاس يمكننا انشاء عدد غير محدوج من الكائنات


2.الكائن (Object):

في عالمنا هذا يمكننا أن نمثل كل شئ على شكل كائن
النباتات و الحيوانات, السيارات .. و حتى الارض


في البرمجة يمكن رؤية الكائن كوحدة في حالة ما و يمكننا القيام بعدة مهمات
مثلا التلفاز يمكننا تمثليه على شكل كائن, لديه حجم, لون , و عدة وظائف كالتشغيل و ايقاف التشغيل.


بعد صنع الكلاسنقوم بانشاء متغيرات (تدعى كائنات) يكون نوعها نفس اسم الكلاس
و هنا نتكلم عن instantiation
مثلا لدينا كلاس اسمها car, ننشئ متغير اسمه myCar و نوعه car

var myCar : Car;


http://3.bp.blogspot.com/-goGoR_aPSk4/VA-pRYYubuI/AAAAAAAAAQY/ph1NKB7JYc8/s1600/manycars.gif


و نقول أن هذا الكائن هو نموذج (instance) للكلاس
و لانشاء نموذج نستعمل الكلمة new ( سنراها في الدرس القادم ان شاء الله)


تذكير: في درس الجداول كنا ننشئها بهذه الطريقة:


var myArray1 :Array=new Array();
var myArray2 :Array=new Array();


- نقول أن الكائنين myArray1 و myArray2 نموذجين (instance) للكلاس Array
-كما نرى فيمكننا صنع الكثير من النماذج بواسطة الكلاس Array (العجينة)

abohmam
06-03-2015, 08:17 PM
السلام عليكم و رحمة الله

مرحبا بكم في درس جديد من دورة تعلم الاكشن سكربت 3

تعلم AS3 - جزء2 [ OOP ] - الدرس 1.2 [الكلاسات و الكائنات]

في الدرس السابق تحدثنا عن الكلاسات و الكائنات لكن ليس بصفة نظرية

قلنا انه بامكاننا صنع نوع جديد من المتغيرات وهذا عن طريق انشاء الكلاسات

و قلنا -انها كالعجيبنة التي تمكننا من صنع الكثير من الكائنات من نفس النوع
في هذا الدرس سنقوم بتطبيق تلك المفاهيم على الاكشن سكربت 3
خطوة بـ خطوة
______________________________

كيفية صنع كلاس في الاكشن سكربت3 (Syntax) :


package //class directory
{
public class name
{
//attributes
//methodes
}
}

___________________________

Package
معمولة لتسهل علينا البرمجة حيث يتم وضع مجموعة كلاسات من نفس الموضوع
داخل نفس المجلد
و هذا يجعل مشروعنا اكثر تنظيما و أناقة فمثلا لدينا الكثير من الكلاسات
و لدينا كلاسات تخص لاعبنا
نريد انشاء كلاس جديدة اسمها character
نقوم بانشاء مجلد اسمه player

ثم نقوم بانشاء الكلاس character داخل مجلد player ليصبح الكود هكذا


package player
{
public class character
{
//attributes & methods
}
}

______________________________


تطبيق

سنقوم بانشاء أول كلاس لنا
في الاكشن سكربت 3 الكلاسات يتم انشاءها في ملفات من نوع.as
اتبع الخطوات التالية:

1.قم بانشاء مشروع جديد من نوع ActionScript3

http://4.bp.blogspot.com/-lJg_d0tSO7E/VA-w-tIkCDI/AAAAAAAAAQo/Lv_NcaFUEHk/s1600/Flash_New_Project.png

2.قم بحفظ المشروع في مجلد
3.قم بانشاء كلاس جديد
File -> new.. -> ActionScript 3.0 Class
و اعطيها اسمplayer
4.قم بحفظها داخل نفس مجلد المشروع

سنلاحظ انه تشكل لنا هذا الكود


package
}
public class player
}
public function player()
{
//constructor code
}
}
}

الان عد الى المشروع و اضغط على اطار لكتابة أكواد الاكشن سكربت 3 من TIMELINE

و اكتب ما يلي

var p1: player = new player();
trace(p1 is player );


نقوم بتشغيل البرنامج عن طريق
Ctrl + enter
او
Control -> Test Scene
سيكتب لنا true


يعني ان p1 من نوع player
كما نرى قمنا بنشاء نوع جديد من الكائنات
نقول أن p1 هوinstance للكلاسplayer

لايمكن انشاء كائن او متغير له اسم كلاس

يعني ممنوع كتابة

var player: player = new player();
___________________________

ماذا حدث بالظبط؟؟

سندرس هذا السطر

var p1: player =new player();

var p1: player;

فلنفرض انه لا وجود لnew player()
قمنا بانشاء كائن من نوع playerدون اعطاء قيمة
لحد الان هذا الكائنا قيمتهnull
(القيمة الافتراضية كما رأينا في الدرس الثاني من الجزء الأول )

= new player();

هنا قمنا بانشاء الكائن

المترجم يدخل الى الكلاس player
و يقوم بتنفيذ الدالة player اوتوماتيكيا
هذه الدالة لها نفس اسم الكلاس و هي اجبارية حتى لو كانت فارغة
تدعى ب constructor

قبل قليل عندما انشأنا الكلاس
كانت هناك دالة لها نفس اسم الكلاس و مكتوب داخلها
constructor code
و هي اول دالة تنفذ عند انشاء كائن جديد


لكي نتأكد من هذا نقوم بالدخول الى الكلاسplayer مرة اخرى
و نكتب هذا الكود داخلconstructor

trace(‘constructor executed!‘);


لتصبح الكلاس هكذا


package
{
public class player()
{
public function player()
{
trace(‘constructor exectued!’);
}
}
{


الان نعيد تشغيل البرنامج بctrl + enter

نرى أنه يكتب لنا
Constructor executed!

و هذا يدل ان ال method
()player قد تم استدعاءها اوتوماتيكيا

___________________________

في الدرس القادم سنكمل هذه الكلاس و سنضع فيها
بعض المتغيرات و الدوال

abohmam
06-03-2015, 08:18 PM
السلام عليكم و رحمة الله

مرحبا بكم في درس جديد من دورة تعلم الاكشن سكربت 3

تعلم AS3 - جزء2 [ OOP ] - الدرس 2.2 [الكلاسات و الكائنات]

في الدرس السابق قمنا بانشاء أول كلاس لنا اسمها player

في هذا الدرس سنقوم بتطويرها و سنشرح طريقة استعمالها و كيفية تغيير قيم attributes الخاصة بها واستدعاء الـ methods التي تملكها

http://2.bp.blogspot.com/-74YFJodbhBs/VBBXwZgjmaI/AAAAAAAAAQ0/B7lmmeLYitQ/s1600/manycars.gif

سنقوم بصنع لعبة بسيطة جدا وهي انشاء لاعبين
حيث أن كل لاعب لديه اسم و نقاط خبرة و حياة
و كل لاعب بامكانه مهاجمة لاعب اخر و في كل هجمة تتضاعف نقاط خبرته الى الضعف اذا لم تكن معدومة و الا سيتحصل على نقطة واحدة
و كل لاعب يتلقى هجمة من الاعب الاخر و تنقص قيمة حياته نفس قيمة الخبرة التي يملكها الاعب المتعدي
اذا وصلت نقاط الحياة الى 0 او اقل يموت الاعب
مثلا:

الاعب 1 يملك 0 نقاط خبرة
الاعب 2 يملك 0 نقاط خبرة
كلاهما يملكان حياة قيمتها 100
سيناريو :
الاعب 1 يهاجم الاعب 2
اذن نقاط خبرة الاعب واحد ستصبح نقطة واحدة لانها حاليا معدومة
الاعب 2 يتلقي الضربة و تنقص حياته نفس قيمة خبرة الاعب1 يعني ستصبح 99
-الاعب 1 يهاجم الاعب 2 مجددا
اذن نقاط خبرة الاعب1 ستتضاعف لانها ليست معدومة و ستصبح 1*2 يعني 2
الاعب2 يتلقى الهجمة و تنقص قيمته ب 2 و تصبح 97
...
و هكذا الى ان تصل قيمة حياة واحد منهما الى 0 أو أقل

__________________________________

حسنا ما هي ال attributes و methods الازمة التي يمكن استنتاجها من الفقرة السابقة؟
كل لاعب لديه اسم اذن هناك attribute من نوع String
كل لاعب لديه نقاط خبرة و حياة اذن هناك attribute للخبرة فليكن xp و الاخر للحياة life
كلاهما من نوع int
كل لاعب يهاجم و يتلقى ضربات اذن هناك method للمهاجمة ()attack و الاخر لتلقي الضربات ()receive
و كل لاعب يموت ()die
_______________________________

الكود
نفتح نفس الكلاس السابق و نقوم بتعديله

package
{
public class player
{
//attributes
var playerName:String;
var xp:int;
var life:int;
//methods

public function player(playerName :String= "player_anonyme")
{
//constructor
/*
هذه أول method يتم تنفيذها اوتوماتكيا مع انشاء الكائن (()new player)
*/
this.playerName = playerName;
xp = 0;
life = 100;
}
public function attack( p2:player):void
{
if( xp == 0)
xp = 1;
else
xp = xp * 2;

p2.receive(xp);
}
public function receive(xp:int):void
{
life = life - xp;
if(life <= 0)
die();
}
public function die():void
{
trace(this.playerName + " is died!");
}
}
}


ملاحظات مهمة بخصوص ال constructor :

فيه يتم عمل initialisation لكل المتغيرات و نقصد بها القيمة الابتدائية لكل attributes
1.
نلاحظ اننا نملك attribute اسمه playerName
و لدينا مدخل اسمه playerName أي نفس الاسم
كيف نفرق بينهما؟
الحل هو this الذي يعني اننا سنتعمل attribute موجود داخل الكلاس
و هو اجباري فهذا النوع من المواقف لكي نفرق بين المتغيرين
هل playerName هو ذلك الخاص بالمدخل ام attribute
الكلمة this ليست اجبارية في مواقف اخرى يمكن وضعها و يمكن الاستغناء عنها
لكن من الافضل كتابها
2.
نلاحظ ان المدخل اختياري مثلما رأينا في درس الدوال
و هنا عند انشاء instance لل player يمكننا اعطاء مدخل و سيأخذ playerName نفس قيمته
و في حالة عدم اعطاء مدخل سيكون اسمه player_anonyme

الدالة attack نضع فيها الاعب الثاني في المدخل (نوع player)
لان بعد مهاجته سيكون (الاعب الثاني) باستدعاء الدالة receive لكي تنقص قيمة حياته
________________________________

سنقوم بانشاء زوجين من instance ل player
حيث يقوم الاعب 1 بمهاجمة الاعب 2
الاعب 2 يلزمه 7 ضربات لكي يموت
(الضربة الاولى تنقص له نقطة لتصبح نقاط حياته 99
الثانية 97
الثالثة 93
..الخ)

نعود الى timeline لانشاء لاعبين

var p1 : player = new player("player 1 ");
var p2 : player = new player("player2");
for(vari:int = 0 ; i<7; i++)
p1.attack(p2);

في الاخير سيكتب لنا

player2 is died
____________________________________

كيفية الدخول الى attributes و methods الخاصة بالكائن من كلاس اخر :

نقصد بهذا كيف نقوم بتنفيذ method
أو قراءة أو تغيير قيمة attribute

كما رأينا في الكود السابق

p1.attack(p2);

قمنا باستدعاء الدالة attack الخاصة بالكائن p1 و ذلك بفصل اسم الكائن و اسم الدالة بنقطة
طبعا مع احترام ترتيب و عدد المداخل الخاص ب method مثلما كنا نرى سابقا

اظن أننا متعودون على هذا فلقد سبق و أن استعملناها في درس الجداول عندما كنا نستدعي الدوال push , pop, shift, splice..
اذن تلك الدوال تخص الكلاس Array التي تم برمجتها من طرف مطوري الاكشن سكربت!
____________________

نفس الشئ اذا اردنا الدخول الى attributes خاصة بالكائن
الفرق بين استدعاء attribute و method:
ال method تمتلك مداخل (و قد لا تملك)
عموما تنتهي بقوسين

object.method();

لكن ال attribut لا نضع فيه اقواس
مثلما كنا نرى في درس الجداول مع المتغير length

myArray.length

كنا ندخل الى attribute اسمه length و الذي يحتوي على عدد الخانات (طول الجدول)
_________________________________

الان سأطرح عليكم هذا الكود و قوموا بتجريبه قبل الدخول الى الدرس القادم
أطلب منكم تغيير كود timeline لاظهار قيمة life الخاصة بالاعب p1
يعني

var p1 : player = new player("player 1");
trace(p1.life);

abohmam
06-03-2015, 08:18 PM
السلام عليكم و رحمة الله

مرحبا بكم في درس جديد من دورة تعلم الاكشن سكربت3

تعلم AS3 - جزء2 [ OOP ] - الدرس 3 [خصائص الدوال و المتغيرات]

http://2.bp.blogspot.com/-T60t1KGImTc/VBCHbrwoStI/AAAAAAAAARU/3mA3fjufLrk/s1600/eye-24-128.png

في الدرس السابق طلبت منكم انشاء كلاس player
و كتابة هذا الكود داخل ال timeline

var p1 : player = new player("player 1");
trace(p1.life);

و النتيجة كانت كما تبينه الصورة

http://4.bp.blogspot.com/-tHtsZILziRw/VBBYhl65B9I/AAAAAAAAAQ8/1-SKApr2JYk/s1600/err.jpg

1178: Attempted access of inaccessible property life through a reference with static type player.

يعني أن الدخول الى attribute اسمه life غير مسموح لنا.

غير مسموح يعني أننا لا نستطيع قراءة محتواه و لا تغييره من timeline
____________________________

من الذي منعنا من الدخول اليها؟ و لماذا؟
هل هو مشكل؟ و كيف يتم حله؟

يجب أن أقول ان لكل متغير و دالة في الأكشن سكربت 3 خصوصيات
و هناك 5 خصائص و هي:

internal: يمكن قراءة أو تغيير المحتوى فقط من كلاسات أخرى من نفس ال package.
public: المحتوى يمكن دخوله من أي كلاس اخر.
private : يمكن دخوله فقط من الكلاس الخاص به.
protected: يمكن دخول المحتوى من نفس الكلاس الخاص به و الكلاسات المشتقة منه (سنرى هذا في درس لاحق)
static: هذه الكلمة تجعل المتغير عام (global) و يتم دخوله بكتابة اسم الكلاس و ليس اسم ال instance
(سنشرحه في الاسفل)

و نكتبها قبل كلمة var بهذا الشكل

property var varName:type;

لكننا في الكود السابق لم نعطي للمتغير أي خاصية !

في الاكشن سكربت 3, اذا لم نعطي للمتغير أي خاصية من الخواص الخمس التي ذكرناها
فان المترجم يعتبره internal و هذا ما يعني أن الوصول اليها يكون فقط من كلاسات من نفس ال package.

و منه نستننج أن الكود المكتوب داخل timeline ليس من نفس الحزمة (package)
الموجودة فيها كلاس player.
_____________________

مهم ! :

عند تشغيل البرنامج (بالضغط على CTRL +R ) أول الأكواد التي يتم تنفيذها هي الأكواد
الموجودة داخل ال timeline .

هناك الكثير من أنواع لغات البرمجة... سأتكلم عن نوعين و هما
لغات من نوع البرمجة الكائنية (oriented object programming) مثل جافا و الاكشن سكربت ..الخ
لغات عبارة عن مجموعة دوال نقوم بكتابتها ثم استعمالها مثل لغة C

كلاهما يملكان دالة أساسية بحيث تكون هي أول دالة تنفذ تلقائيا
نقول أنها نقطة دخول البرنامج
أي منها يبدأ البرنامج
مثلا في C و جافا الدالة لها اسم main

في الأكشن سكربت 3 الكلاس الرئيسي (نقطة الدخول) هو MainTimeline
اكوادها مكتوبة داخل ال timeline

هل نحن مجبرون على كتابة أكواد نقطة الدخول في timeline؟

الجواب هو لا.. فيمكننا كتابة كلاس اخر من انشائنا بحيث منه يبدأ برنامجنا
سنشرح الطريقة في جزء اخر, لحد الان سنكتب الاكواد داخل timeline
___________________

عد الى كود الكلاس player
ثم قم بتغيير المتغير life الى public
يعني:

public var life:int;

أعد تشغيل البرنامج تاركا الكود السابق في timeline


var p1 : player = new player("player 1");
trace(p1.life);

و سترى انه يمكننا الان الدخول الى المتغير life لما وضعنا الخاصية public ! وقمنا بقراءة محتواه
فالان يمكننا قراءة و تغييره كما نريد


var p1 : player = new player("player 1");
p1.life = 50;
trace(p1.life);
_______________________________

هل من الأفضل دائما كتابة المتغيرات على شكل public؟
و هكذا يمكننا قراءتها و تغييرها من أي مكان...
فما الفائدة من الخصائص الاخرى..

لحسن الحظ أن الخصائص الاخرى مثل private , protected.. موجودة
و إلا فبامكاننا ارتكاب أخطاء فاذحة و نصدم بنتائج غير متوقة بالرغم من أن الكود صحيح
فالخصائص معمولة لحماية المستخدمين عند تغييرهم لقيمة المتغير
و المستخدمون في هذه الحالة هم مستخدموا الكلاسات -أي المبرمجون- و ليس مستخدموا البرنامج

و قد تكون الحماية ضدك أنت بالرغم من أنك صاحب الكلاس
فبعد مرور زمن طويل قد تنسى أو لا تنتبه و تقوم بتغيير قيمة المتغير بطريقة غير صحيحة

اليكم هذا السيناريو :

- قام أحمد بانشاء كلاس تدعى PageGen من اجل صنع صفحات كتابية
هذه الكلاس تحتوي على عدة دوال كاضافة صفحة و حذف صفحة ..الخ
و مجموعة متغيرات منها متغير (global) لحساب عدد الصفحات. فليكن هذا

public static var NB_PAGES : int;

في ال constructor نضيف 1 الى عدد الصفحات (فلقد أنشأنا صفحة جديدة)
- أحمد يقدم الكلاش لأسامة الذي يبرمج معه هذا البرنامج
أسامة لا يهمه كيف قام احمد بصنع تلك الدوال و أي متغيرات يستعمل
كل ما يهمة هو أن الدالة addPage مثلا تقوم باضافة صفحة ..الخ
أسامة يقوم بعرض عدد صفحاته بالدخول مباشرة الى المتغير الخاص بالكلاس NB_PAGES هكذا


trace(PageGen.NB_PAGES);

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

public static var PAGES_ARRAY:Array;

يستلم أسامة النسخة الجديدة المليئة بالتغييرات إلا أنه سيُصطم بأخطاء أثناء الترجمة
فالمتغير PageGen.NB_PAGE أصبح غير معروف

أسامة يحاول اقناع احمد لارجاع النسخة القديمة لكن احمد سعيد بعمله الجديد و يرفض.
فمن المخطئ؟
أحمد هو المخطئ لأنه جعل التعامل مع المتغيرات مباشر و هذا شئ غير منصوح به
في البرمجة فلو قام أحمد بصنع دالة اسمها getNbPage:
- النسخة الاولى ترجع لنا المتغير NB_PAGES
أسامة يستعمل getNbPage و لا يعلم كيف تعمل بالداخل
- النسخة الثانية ترجع لنا طول الجدول
أسامة يستعمل دائما نفس الدالة و النتيجة دائما صحيحة !
____________

سيناريو 2:

لدينا كلاس User تحتوي على الكثير من المتغيرات
منها private var userName:String
private var pseudo:String
...
userName: اسم المستخدم الحقيقي
pseudo: اسمه الافتراضي

يقوم المستخدم بكتابة اسمه على هذا الشكل CHAfik
طبعا لو نعطي هذه القيمة مباشرة الى المتغير userName سيصبح
userName يحمل القيمة CHAfik
و لكنني كمبرمج أريد أن يكون الحرف الاول كبير و بقية الاحرف صغيرة

اذن الدخول المباشر الى المتغير غير منصوح به هنا أيضا فمن الأفضل
صنع دالة setUserName مثلا و التي نقوم فيها بتعديل الاسم

_____________

- و اذا أردت تغيير متغير private من كلاس اخر؟؟!

سنستعمل الـ getters و setters وهناك طريقتين :

getter/setter الطريقة الأولى :

1.Setter :
سنعود الى السيناريو الثاني
يجب انشاء دالة تقوم بفحص المداخل قبل اعطائه للمتغير

public function setUserName(n : String):void
{
this.userName = n.charAt(0).toUpperCase() + s.substr(1).toLowerCase();
}

نفرض أن المدخل هو chAfiK
(n.charAt(0 سبق وأن رأيناها في درس الجداول و السلاسل الحرفية
و تعني أننا سنذهب الى الحرف الأول
()toUpperCase: تحويل الحرف الى حرف كبير

n.charAt(0).toUpperCase
يعني اننا سنأخذ الحرف الاول و نقوم بتكبيره( لحد الان userName قيمته C)

+ : للـ concatenation يعني اضافة كلمة لكلمة اخرى
(substr(1: هذه الدالة سنتكلم عنها في درس اخر
لكن في هذا المثال ستقوم بحذف الحرف الاول فقط
اذن تعطينا hAfiK
toLowerCase: تحويل الاحرف الى احرف صغيرة
hafik

اذن قمنا باضافة C الى hafik لتصبح Chafik :)

لكتابة قيمة في المتغير نستدعي الدالة بهذا الشكل:
instanceName.setUserName("chafik");

(instanceName اسم الكائن)
_______________

2. Getter:

نبقى دائما مع السيناريو الثاني

في الكود السابق أردنا تغيير قيمة المتغير userName الى chAfiK
لكننا ادخلناه عن طريق دالة كوسيط لتعديله كما أردنا
كيف يمكننا أن نقرأ محتواه الان ؟
لو حاولنا الدخول اليه مباشرة فلن نستطيع لأنه private

trace(p1.userName);

يلزمنا من اجل هذا كتابة دالة داخل الكلاس و التي تقوم بارجاع قيمة المتغير
بما ان الدالة موجودة داخل الكلاس اذن بامكانها الدخول الى المتغير private
سنستغل هذا لنرجع قيمة userName بهذه الدالة بهذا الشكل


public function getUserName() : String
{
return (this.userName);
}


كما نرى فالدالة public يعني بامكاننا استدعائها من أي كود
نوعها String يعني ترجع لنا قيمة من نوع سلسلة احرف
و هكذا نحصل على قيمة userName :)

لفحص ما يحتويه المتغير userName نعمل الاتي

trace( instanceName.getUserName() );
____________________________________

2.الطريقة الثانية getter/setter :

في الطريقة السابقة كنا نغير/نقرأ قيم المتغيرات باستدعاء الدوال المخصص

instance.setVar(value);
instance.getValue();

لكن هناك طريقة اخرى للكتابة و القراءة كما لو كانت المتغيرات public مثلا

instance.attribute = value;
trace(instance.attribute);

كما نرى لاوجود للقوسين ...

و ذلك باستعمال الكلمة الدلالية set / get :
1.set
: الهدف منها هو كتابة قيمة داخل المتغير المراد مثلما رأينا سابقا و يجب ان تحتوي على مدخل واحد على الاقل و الا سيكون هناك خطأ في الترجمة


public function set userName(n:String):
{
this._userName = n.charAt(0).toUpperCase() + n.substr(1).toLowerCase();
}

يجب تغيير اسم المتغير من userName الى userName_ (مثلا) او اي اسم اخر
لانه يُمنع كتابة دالة لها نفس اسم متغير
اذن للدخول الى المتغير userName_ نقوم بالتالي

instanceName.userName = value;

value: القيمة المراد ادخالها
_________________

2.get :

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

public function get userName():String
{
return this._userName;
}

للحصول على قيمة ال userName

trace(instanceName.userName);

ما قمنا بشرحه يسمى ب Encapsulation و يعني اخفاء المتغيرات و هذا جد مهم
___________________________________________


لحد الان تعرفنا على الخصائص internal و public و private

الخاصية protected تعني أن المتغيرات يمكننا الدخول اليها من الكلاس الموجودة فيه (مثلما رأينا مع private)
و أيضا من الكلاسات المشتقة منها (و سنرى هذا لما ندخل في درس التوريث, inheritance او héritage بالفرنسية)

static:

كلمة static تجعلنا ندخل الى المتغير عن طريق اسم الكلاس و ليس ال instance
و نقصد بهذا انها سيكون متغير عام (global) و لا يخص فقط الكائن و سنشرحه بالتفصيل في هذا الدرس

سابقا عندما أنشأنا الكائنين p1 و p2 ثم قام الاعب 1 بمهاجمة الاعب 2
كان هناك تغير اختلاف في قيم كل لاعب
يعني المتغيرات الخاصة بالكائن p1 كانت لها قيم
أما الكائن p2 فكانت له هو أيضا قيما اخرى
مثلا p1.life تساوي 100
p2.life تساوي 99

http://4.bp.blogspot.com/-HeIfgit3kAw/VBCDBibdIdI/AAAAAAAAARM/gUp62bU8bV0/s1600/err.jpg

للدخول الى قيمة life الخاصة بالاعب نكتب اسم الاعب . المتغير

p1.life
p2.life
...

الان نعود الى الكلاس player
و نضيف هذا ال attribute في الاعلى امام المتغيرات الاخرى
اسمه counter و الهدف منه هو حساب عدد الاعبين
يعني في كل مرة ننشئ لاعبا جديدا نضيف قيمة 1 الى المتغير counter

public static var counter: uint= 0;


الان نغير ال constructor


public function player(playerName :String= "player_anonyme")
{
this.playerName = playerName;
xp = 0;
life = 100;
player.counter++;
}


المتغير counter هو static اذن يمنع كتابة this.counter داخل الكلاس فهو لن يخص أي كائن و انما الكلاس
ثم ندخل الى ال timeline و نكتب

var p1 : player = new player("Player1");
var p2 : player = new player("Player2");
trace( player.counter);

سكتب لنا 2

كما نلاحظ فان المتغير counter تم استدعاؤه عن طريق اسم الكلاس و ليس الكائن

بامكاننا أيضا اعطاءها خصوصيات اخرى مثل private static
(و هو ما ينصح به في هذا المثال فالمتغير counter بما انه public بامكاننا تغييره
من كلاس اخر مثلا

player.counter = 50;

بالرغم اننا نملك فقط لاعبين
اذن من الافضل أن تكون private و في نفس الوقت صنع getter لمعرفة القيمة
فقط دون وضع setter)

و لكل مبرمج الحرية و طريقة تفكير خاصة به

abohmam
06-03-2015, 08:18 PM
السلام عليكم و رحمة الله

مرحبا بكم في درس جديد من دورة تعلم الاكشن سكربت 3

تعلم AS3 - جزء2 [ OOP ] - الدرس 4 [التوريث inheritance]

http://2.bp.blogspot.com/-Oek6ijc7IpU/VBl4DfQ2PsI/AAAAAAAAASM/stjc5Ic0v-Y/s1600/is-a.png

في هذا الدرس سنرى مفهوما جديدا و مهما في البرمجة الكائنية و هو التوريث

__________________

كلمة توريث مأخوذة من العالم الحي
كل عنصر في العالم يأخذ خصائص عنصر اخر
مثلا الانسان له الكثير من خصائص الثدييات (الانسان يرث من الثدييات)
الموز له خصائص الفواكه (الموز يرث من الفواكه تلك الخصائص)

يُستعمل التوريث في العلاقات من نوع "is a" أي "هو.."
مثلا في لعبة ما لدينا الاعبون العاديون(player) و المشرفون على اللعبة(admin)
المشرفون 'هم لاعبون' (فهم يملكون نفس الخصائص)

المشرف يرث كل خصائص الاعب العادي
الكلاس player تدعى الكلاس الأم أو سوبر كلاس (super class)
و الكلاس admin تدعى الكلاس البنت (sub-class)

_______________________

الوراثة في الأكشن سكربت 3 :

لكي ترث كلاس نفس خصائص كلاس اخر نستعمل الكلمة الدلالية

extends

مثال الكلاس admin ترث من الكلاس player

package
{
public class admin extends player
{
public function admin()
{
// constructor code
}
}
}

الان لكي ننشئ instance للكلاس admin نستعمل نفس الطريقة السابقة نذهب الى timeline و نكتب الكود

var myAdmin : admin = new admin();


اذا جربنا هذا الكود ستظهر لنا رسالة خطأ 1203

عندما ترث كلاس بنت من كلاس أم
يجب علينا أن نمرّ على ال constructor الخاص بالأم مع احترام المداخل الخاص به

لكي ندخل الى constructor الخاص بالأم نستعمل الكلمة super
_______________________

التوريث في الأكشن سكربت 3 :

لكي ترث كلاس نفس خصائص كلاس اخر نستعمل الكلمة الدلالية

extends

مثال الكلاس admin ترث من الكلاس player


package
{
public class admin extends player
{
public function admin()
{
super();
}
}
}

_________________________

الهدف من التوريث :

فلنفرض ان في الكلاس player هذه المتغيرات


var playerName:String;
var xp:int;
var life:int;


و هذه الدوال

public function attack( p2:player):void
public function receive(xp:int):void
public function die():void



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

عوضا ان ننشئ كلاس admin نضع بداخلها المتغيرات

var playerName:String;
var xp:int;
var life:int;

و الدوال

public function attack( p2:player):void
public function receive(xp:int):void
public function die():void


يكفي أن نستعمل extends و ستأخذ الكلاس admin كل خصائص الكلاس player

__________________________________

مثال اخر

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

عوضا أن ننشئ الكلاسات الثلاث و نكتب نفس المتغيرات و الدوال في كل كلاس مثلا

var maxSpeed
var sound
..

.function set MaxSpeed(s:int):void
function get MaxSpeed():int

....

يكفي انشاء كلاس animal و وضع كل الخصائص
ثم نستعمل extends لكي ترث باقي الكلاسات منها
public class lion extends animal
public class dog extends animal
..
______________________________

: super-types / sub-types

بفضل التوريث الكلاس admin تملك نوعين
player : يعتبر super-type
admin: يعتبر sub-type

لو نكتب الكود التالي

var myAdmin : admin = new admin();
trace(myAdmin is admin); //true
trace(myAdmin is player); //true

سيظهر لنا true و هذا يعني أن myAdmin هو admin و player

كلما قمنا بتوسيع ال super type (توسيع يعني هناك كلاسات ترث منه)
يمكننا تمرير instance من sub-type
يعني المتغيرات من نوع player يمكنها تخزين كائنات من نوع admin

مثال

var myAdmin : player = new admin();
trace(myAdmin is admin); //true
trace(myAdmin is player); //true



كل admin هو player

المترجم يعلم ان كل الخصائص الموجودة في player هي موجودة أيضا في admin

العكس غير صحيح

var myAdmin : admin = new player();

_________________________

ما الفائدة من تمرير متغير sub type الى متغير super type؟

فلنفرض أننا نملك دالة ترجع لنا أنواع مختلفة من الكائنات

مثلا
getBestPlayer():player

هذه الدالة مثلا ترجع لنا أقوى لاعب في اللعبة من نوع player
لكن قد يكون أقوى لاعب من نوع admin أو نوع اخر
يمكننا و بدون أي مشكل ارجاع أحسن لاعب مهما كان نوعه player او admin

return (admin_type);

مثال اخر

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

public function getChildAt(index:int):DisplayObject

هناك الكثير من المتغيرات الجرافيكية مثل
shape MovieClip Sprite SimpleButton

كل هذه الانواع ترث من الكلاس DisplayObject و لهذا فإن تلك الدالة ترجع لنا مختلف الانواع الجرافيكية

______________


ماذا لو جربنا الكود التالي؟


نفرض أن في الكلاس admin الدالة التالية

banPlayer(p:player):void

الهدف منها طرد لاعب لسبب معين

هل هذا الكود صحيح؟

var playerHacker : player = new player();
var myAdmin : player = new admin();
myAdmin.banPlayer(playerHacker);


اذا جربنا هذا الكود سنقع في رسالة خطأ 1061

الكلاس player لا تملك الدالة banPlayer بالرغم من أننا مررنا للمتغير myAdmin كائن من نوع admin

لكي نتمكل من تنفيذ الدالة banPlayer نستعمل نفس الطريقة التي رأيناها في درس المتغيرات (casting)
هكذا
type ( myObject)

ليصبح الكود هكذا


var playerHacker : player = new player();
var myAdmin : player = new admin();

admin( myAdmin ).banPlayer(playerHacker);



هذه المفاهيم في البرمجة الكائنية تدعى Polymorphism
____________

تعديل دالة موروثة (override) :

عندما نرث من كلاس معينة فاننا نرث كل المتغيرات و الدوال الخاص بالكلاس الأم

لكن أحيانا نحتاج الى تغيير دالة ما كإضافة بعض الاكواد مثلا

فلنفرض أن في الكلاس player لدينا دالة introduceMySelf
حيث سنظهر فيها اسم الاعب

public function introduceMySelf():void
{
trace("my name is :"+ this.playerName);
}

أنا في الكلاس admin عوضا أن أظهر اسم الاعب أريد أن أظهر رسالة i'm admin

override public function introduceMySelf():void
{
trace("I'm admin!");
}

ملاحظة مهمة:
الدالة المعدلة يجب أن تملك نفس اسم و المداخل و نوع ارجاع الدالة الام


عندما نعدل دالة ما فهذا لن يفقدنا الدالة الموروثة .يمكننا الدخول الى الدالة الام عن طريق الكلمة super

override public function introduceMySelf():void
{
super.introduceMySelf(); // الدخول الى الدالة الام و التي تظهر اسم الاعب
trace("I'm admin!");
}



نلتقي في الدرس القادم ان شاء الله

abohmam
06-03-2015, 08:18 PM
السلام عليكم و رحمة الله

مرحبا بكم في درس جديد من دورة تعلم الاكشن سكربت 3

تعلم AS3 - جزء2 [ OOP ] - الدرس 5 [كلاسات جاهزة و مهمة]

سنرى في هذا الدرس بعض الكلاسات المهمة و الجاهزة في الاكشن سكربت 3 والتي قد نحتاجها في أي وقت

http://3.bp.blogspot.com/-ihU-l7zRYOg/VF4uOHDkPlI/AAAAAAAAASc/tT-2f8H8FNI/s1600/As3-222x180-25176_186x180.png

يجب معرفة معنى الكلاس و الخصائص ( كما سبق و رأينا في الدروس السابقة)
و كيفية انشاء كائن خاص بالكلاس قبل قراءة هذا الدرس
و أيضا فهم الداول و المداخل

مثلا:

functionName(param: int):Number

هذه الدالة اسمها fuctionName تأخذ مدخلا واحدا من نوع int و ترجع لنا قيمة من نوع Number


functionName(param: int = 5 ):Number

مثل الدالة السابقة لكن الفرق هنا أن المدخل ليس اجباري ففي حالة عدم وضعه سيأخذ القيمة 5

يعني عندما نستدعي هذه الدالة بهذه الطريقة

functionName();
كأننا استدعيناها هكذا
functionName(5);

_____________________________

String

هذه الكلاس سبق و ان رأيناها في الجزء الأول و هي الخاصة بالسلاسل الحرفية

أهم الدوال (methods) الخاصة بالكلاس String:

charAt(index:Number = 0):String : ترجع لنا الحرف الموجود في الموقع المحدد بالمدخل index

charCodeAt(index:Number = 0):Number : ترجع لنا رقم الحرف الموجود في الاندكس المعطى

الذاكرة المركزية تخزن كل شئ على شكل أعداد فلا يمكن كتابة 'a' داخل الذاكرة
و انما يتم تخزينه بالعدد 97 و هذا الكود يدعى كود ASCII
لما نريد اظهار الحرف a يقوم الكمبيوتر بتحويله من 97 الى الحرف a
كل حرف له كود خاص به اضعط هنا لرؤية بعض الاحرف و الاكواد الخاصة بها

concat(... args):String : هذه الدالة تأخذ عدة سلاسل حرفية كمدخل -او سلسلة واحدة- و ترجعها لنا على شكل سلسلة واحدة يعني انها تفوم بالصاقها, مثلا


var a:String = "a";
var b:String = "b";
var c:String = "c";
var abc:String = a.concat(b,c);
trace(abc); // abc
trace(a); //a


كما نرى فالمتغير abc قيمته "abc" فلقد تم الصاق قيمة المتغيرات aو b و c في سلسلة واحدة
دون تغيير قيمتهم الأصلية (يعني المتغير a قيمته تبقى دائما "a" .. )

toLowerCase():String : ترجع لنا الاحرف الصغيرة
toUpperCase():String : ترجع لنا الاحرف الكبيرة

__________________

أهم attribute
length : int : يحتوي على طول السلسلة الحرفية (عدد الاحرف)


لمزيد من المعلومات حول الكلاس String اضغط هنا (http://help.adobe.com/en_US/FlashPlatform/reference/actionscript/3/String.html)
______________________________

سأذكر بعض الكلاسات الاخرى المهمة مع وضع رابط مباشر للموقع adobe التي يحتوي على الشرح


Array
Math
DisplayObject
MovieClip(سنراه في الجزء القادم)
Object
Bitmap (سنخصص لها جزءا كاملا)
Timer

الموقع الرسمي (http://help.adobe.com/en_US/FlashPlatform/reference/actionscript/3/class-summary.html)

azizsoft
06-03-2015, 08:51 PM
الحمدلله والصلاة والسلام على رسول الله وعلى آله وصحبه أجمعين
بارك الله فيكم أستاذ أبو همام ونفع بكم :abc_022:

كريم جودي
07-03-2015, 09:29 AM
بارك الله فيك أخينا أبو همام

أبو يوسف
07-03-2015, 03:01 PM
بارك الله فيك اخي أبو همام على هذا الجهد الرائع

:teslam:

أبو فارس
09-03-2015, 05:23 PM
شـكــ وبارك الله فيك ـــرا لك ... لك مني أجمل تحية .

خادم المسلمين
15-06-2018, 12:50 AM
:abc_028::abc_028: