مقدمة
السلام عليكم ورحمة الله وبركاته، في الـ tutorial دي هنتكلم عن شئ مهم جداً وهو ازاي تفكر بطريقة الـ OO.. ايه طريقة الـ OO دي ياعم؟ دي الـ Object Oriented وهنشرح كل شئ متعلق بيها بالتفاصيل خلال الـ tutorial دي .. وهعطي أمثلة لبرامج بسيطة عشان الأمور توضح.. بس أهم حاجه عندي في الـ tutorial دي هو انك تتعلم ازاي تفكر بالـ Object Oriented. وطبعا الجزء ده (اللي بنشرحه حالياً) هيكون مقدمة بسيطة عشان نفتح الأمور لـ بعد كده.
وقبل ما ندخل في الشرح عاوز أفهمك الفرق ما بين الـ OO والـ OOD والـ OOP بشكل بسيط أوي.
- الـ OO هي طريقة تفكير بنبص ليها للعالم، مرحلة التفكير والتحليل قبل ما تـ design أو حتى تـ Code، بتفكر في مكونات الـ System بتاعك.
- الـ OOD (Object-Oriented Paradigm) بتحول الرسوم اللي كانت في مخك دي لـ رسومات، ودي مرحلة قبل كتابة الكود.
- الـ OOP (Object-Oriented Programming) هي مرحلة كتابة الكود بـ لغة برمجة بتدعم المفاهيم أو الـ Concepts بتاعت الـ OOD زي الـ Java أو الـ C# ألخ..
هنشرح أيه؟
هنشرح فالمقدمة دي أعمدة الـOOD واللي لازم بالطبع عشان لغة تقول عنها انها Object Oriented Language لازم تـوفر الـ Concepts دي.. وهما:
- الـ Encapsulation
- الـ Inheritance
- الـ Polymorphism
- الـ Composition
- الـ Abstraction
هنشرح الـ Concepts دي فالبداية عشان بعد كده نستخدمهم لفهم حاجات أكبر. فاقرأ بتمعن. وعاوزك تكون فاهم ولو شوية من الـ OOD.
ليه الـ OO ؟
زمان قبل ما يظهر الـ OO كان السائد وقتها هو الـ Structured/Procedural Programming زي البرامج اللي بتتعمل بالـ C والـ OO مجاش زي ما انت متوقع عشان يستبدل الـ Structured/Procedural Programming.. بل في عادي برامج شغالة بالـ Structured/Procedural Programming وشغالة زي الفل وبتأدي وظيفتها بأكمل وجه.. ومش لازم حتى تغير الأنظمة دي لـ OO لمجرد بس التغيير لأنه هيكون خطر (risky) أوي أصلاً، فـ لازم نفكر كويس اوي اوي قبل ما نستخدم الـ OO.. فالحاجه اللي شغالة كويس سيبها زي ما هي، إلا لو في سبب قوي للتغيير.
كمان في بداية إنتشار الـ OO.. ظهر موضوع إن الـ OO databases هتحل محل الـ relational databases (زي الـ MySQL والـ SQL Server) بس ده محصلش.. فـ ليه بقى، لأن مكنش في سبب مقنع ان الناس تحول من الـ Relational Database للـ OO Database، طالما الدنيا شغالة كويس جداً وكمان التغيير ده هيخسر كتير ومخاطره كبيره، فـ بلاش منه، إلا زي ما قولت في سبب مقنع اوي اوي للتغيير. ودلوقتي أصلاً أغلب الـ Development او تطوير البرمجيات فيها خليط من كذا Paradigm زي الـ Structured/Procedural والـ OO.
طب يا عم ماشي، انت لسه مجاوبتش على ليه الـ OO؟ تمام.. بإختصار الـ OO ظهر عشان تسد فجوة كانت موجودة ايام الـ Structured Programming/Procedural اللي هي كنا بنفكر ساعتها في البرنامج على انه مجرد مجموعة من الـ Functions أو مجرد مجموعة من الخطوات بتم على Data والحاجات دي “منفصله عن بعضها”.. لكن في الواقع العملي الحاجات دي مش منفصله عن بعضها ولا حاجه بل هي مرتبطه بـ بعض فكنا عاوزين طريقة من التفكير تغير لينا الـإتجاه ده، وكمان الـ Complexity بتاعت الـ Programs بدأت تزيد جداً وبدأنا نفشل فإننا ندير التعقيد ده، عشان كده الـ OO ظهرت عشان تسد الفجوة دي.. أولاً هي بتقدمك طريقة عشان تجمع فيها البيانات (Attributes) والعمليات (Methods) اللي بتم على البيانات (Attributes) في شئ واحد بنسميه Object.. ونجحت في انها تـحل نقطة التعقيد دي وانها تجمع كل شئ related بـ بعده في مكان واحد.
ايه هو الـ Object؟
الـ Object هي طريقة بننظر ليها للأشياء من بُعدين، فمثلاً .. الإنسان كـ Object هو صفات، يعني ايه ؟ صفات زي الطول والعمر ولون عينه وهكذا.. الـ Object ده برده له Behaviors زي انه قادر يمشي ويتكلم ويتنفس. فالـ Object بنوصفه من خلال بعدين هما الـ Data بتاعت الـ Object دي زي الـطول والعمر، ألخ.. وكمان تصرفات أو Behaviors والـ Behaviors دي بنمثلها بـ Functions/Methods برده في الـ OOP. وده كله عكس الـ Structured/Procedural Programming اللي بيكون متكون من Functions منفصله تماماً عن بعضها.
والميزة اللي بيوفرها الـ OO هو انك تقدر تتحكم في مين يقدر يوصل لبياناتك فمثلاً في الـ C انت ممكن تعمل struct لـ Person وتديله شوية بيانات زي كده:-
struct Person
{
int Age;
float Height;
};
وانت بالطبع مش عاوز حد يكون له access على الـ age دي عشان ميغيرش فيها.. وتكون بياناتك مظبوطة او تكون بياناتك بتحقق السلامة او يكون في مفهوم سلامة البيانات أو الـ Integrity.
الـ OO من أهم مميزاتها هو موضوع انك تتحكم في مين يـ access الـ Data ومين لأ.. عن طريق حاجه بنسميها Access Modifiers في الـ OOP..
وده مثال بالـ C# :-
class Person
{
private int Age;
private float Height;
}
انت بتقول هنا ان أي شخص هيستخدم الـ Class اللي اسمه Person وهيعمل منه Object ملهوش الصلاحية انه يـ access الـ age ولا الـ height لكن انت الوحيد (اللي عامل الـ Class) اللي تقدر تعدل عليهم عن طريق الـ Methods.. طب إزاي ادي الصلاحية لأي Object تاني من خارج الـ Class ده أنه يتحكم في الـ age والـ height؟
أولاً اللي عاوز اقولهولك اللي حققناه فالكود ده اسمه Data Hiding أو إخفاء البيانات والـ Class اللي اسمه Person ده هو الوحيد اللي يقدر يعدل في الـ attribute ده.. وعشان يخلي user للـ Class ده يغير في الـ Age او الـ Height.. بنعمل Method.. مثلاً هنسميها SetAge(int age)
زي كده:-
class Person
{
private int Age;
private float Height;
public void SetAge(int age)
{
this.Age = age;
}
}
ليه نعمل Method تعدل في الـ Age، ما نخليه يعدل في الـ Age attribute وخلاص! بص، تخيل معايا الشخص اللي بيستخدم الـ Class بتاعك واللي عمل منه Object في البرنامج بتاعه وجيه شخص بيستخدم البرنامج بتاعه وخلى الـ age بتاع الشخص 500 سنة مثلاً.. أولاً الـشخص اللي بيستخدم البرنامج بتاع الشخص اللي بيستخدم الـ Class بتاعك هيطفش.. والـشخص اللي بيستخدم الـ Class بتاعك هيدعي عليك وهيعمل issue على github ويفضحك.. فلأ طبعاً.. انا عاوز الـ Class بتاعي يحقق مصطلح الـ Integrity من خلال الـ Data Hiding عشان اتغاضى عن المشاكل دي.. فـ عشان كده بنخلي الـ user ده يستخدم الـ method دي عشان فيها Validation للـ age أو بنشوف القيمة اللي مرتبطه بالـ age منطقية ولا لأ، عشان ميخليش عمر الإنسان 500 سنة مثلاً، فالكود اللي كتبناه فوق هيكون كده:-
class Person
{
private int Age;
private float Height;
public void SetAge(int age)
{
if(age <= 0 && age > 100)
Console.WriteLine("Invalid age");
else
this.Age = age;
}
}
انت كده هتنام مرتاح، والـ Class بتاعك هيكون في حالة صحيحة ومنطقية. وحاجه تانيه مثلاً.. الـ user اللي بيستخدم الـ Class بتاعك راجل محترم (دايما إفترض الاسوء) ومش هيبوظ الـ Class بتاعك ويقعد يلعب فيه.. بل انت اللي غيرت شئ فيه مثلاً غيرت الـ Age لـ PersonAge طبعاً الـ User اللي عامل Object من الـ Class بتاعك البرنامج بتاعه هيضرب وهيحتاج يعدله.. وده لو تعلم شئ خطير جدا جدا، بالذات لو بتعمل شئ بيتعامل مع الـ Hardware وعندك users كتير بتستخدمه.
طبعاً مش عاوز أقولك عشان تستخدم الـ Class ده بتعمل منه Object زي كده:-
Person p = new Person();
كمان الـ Object أكبر بـ كتير من انه يكون Data Structure أو Primitive Data Types زي الـ Integer أو Float، ألخ.. لأنها بتحتوي على Behaviors أو Methods بتلعب على الـ Data اللي موجوده في الـ Object ده أو ممكن تعمل أي Action تاني وبنجمع الـ Data او الـ Attribute و الـ Behaviors/Methods دي كلها مع بعض في Object واحد.
والحاجة الأخيره اللي عاوز اوضحها، هو انك لما تيجي تعمل كذا instantiation من الـ Class ده وبتاخد نسخه منه (وده مفهوم الـ Object) مش شرط بشكل Physically أو مادي أو فيزيائي ان كل نسخة بتكون بالفعل واخدة Space فالميموري، لأ.. ممكن كل Object انت عملته من Class معين بيشاور على الـ Implementation الفعلي او الكود الفعلي بتاع الـ Class ده فالميموري.. ودي مش شغلتك انت هنا دي شغلة الـ Compiler (اللي بيحول الكود اللي انت كاتبه للغة الكمبيوتر) أو الـ Operating System عشان بس يوفروا في الـ Memory ويكون الأداء سريع، انت شغلتك بس انك تفكر في إن كل Object عملته من Class معين هو مختلف تماماً عن الـ Objects التانية، بل هو كيان مستقل بذاته.
يعني ايه الـ Encapsulation ؟
تعرف أصلاً إن أنا شرحت الـ Encapsulation بس انت مخدتش بالك :) الميزة الكبيرة اللي بتقدمها الـ OO هي الـ Encapsulation وبتنطق كده (uhn·kap·syuh·lay·shn) وه المفهوم اللي بتجمع الـ Attributes والـ Behaviors دي مع بعض وبتخلينا برده نعمل الـ Data Hiding ونخلي البيانات نتحكم فيها بس عن طريق الـ Class والـ Methods بتاعتها وده بيحل مشاكل كتير زي موضوع أن الـ Data بتكون منفصله عن الـ Function او الـ Method ودي فيها مشكلة كبير، لأن ده معناه ان الداتا غالباً بتكون Global اي Function في البرنامج ممكن توصلها وده بيخلينا ندخل في حوارات كتير زي اننا نكتشف ايه الـ Function اللي عدلت في الداتا دي بالظبط وعملت مشكله في البرنامج بتاعنا لو حصل مشكلة. فالـ OO حلت المشكلة دي من خلال اننا عملنا زي Packaging أو تغليف للـ Data والـ Methods دي أو الـ Attributes والـ Behaviors .. كلهما نفس المسمى. طب يعني ايه برده الكلام ده كله.. ازاي يعني بتعمل Packaging للـ Attributes والـ Behaviors؟ طب خلينا ناخد مثال، دلوقتي أحنا هنعمل Class اسمه PositiveMathOperations والـ Class ده بيشتغل على الأرقام الموجبه بس.
class PositiveMathOperations
{
}
فالبرنامج بتاعنا ده هيكون فيه رقمين اسمهم num1
و num2
وخلينا نعملهم public ونعمل Function لجمعهم وبرده نعمل Function للضرب والـ Class دي عندنا المفروض بتشتغل بس على الأرقام الموجبه، بس.
class PositiveMathOperations
{
public uint num1;
public uint num2;
public uint Add()
{
return this.num1 + this.num2;
}
public uint Multiply()
{
return this.num1 * this.num2;
}
}
الـ User بقى هيبدأ يستخدم الـ Class بتاعتنا:
PositiveMathOperations calc = new PositiveMathOperations();
الـ User للأسف لعب في الـ Object اللي هو عامله ده وحط قيمة سالبة.
calc.num1 = -5;
calc.num2 = -10;
Console.WriteLine(calc.Add()) // -15
الـ Data Type اللي استخدمتها في الـ num1
و num2
هي uint .. او Unsigned int والـ Data Type دي مش هتقبل رقم سالب والبرنامج عندك هيعمل أيرور لو الرقم ده كان سالب.. فـلو الـ User بيستخدم الـ Class بتاعتك دي عشان يعمل برنامج مثلاً للآله الحاسبه.. وعمل مثلاً سيكشن بتعمل operation على الأرقام السالبة وسيكشن تانيه للأرقام الموجبة.. فلما الشخص العادي يدخل رقم سالب بأي طريقة كانت.. البرنامج اللي عمله الـ user اللي بيستخدم الـ Class بتاعك ده هيضرب! ودي مصيبه! والـ Design اللي انت عملته في الأول خالص انك تفتحها على البحري كده، وفي الحقيقة أصلاً مش بيختلف عن الـ Design بتاع الـ Structured Programming .. وكمان خالفت قواعد الـ OO في الـ Encapsulation.. فالـ صح اللي انت تعمله هو انك تطبق الـ Data Hiding وبالمناسبه الـ Data Hiding هي جزء برده من الـ Encapsulation..
فالـ Design بتاعك يكون بالشكل ده
علامة الـ (-) معناها انه Private بمعنى محدش يقدر يوصله من بره الـ Class وعلامة الـ (+) معناه انه Public وده معناه ان اي حد يقدر يكون له access عليه من بره الـ Class.
حيث أن الـ GetNum1
و GetNum2
هترجع له القيم بتاعت num1
و num2
لو عاوزهم والـ SetNum1
وSetNum2
هتـ assign الـ Value اللي هو حاطتها للـ num1
أو num2
وهتتأكد هما قيم صحيحة ولا لأ (Validation).
والصورة دي بالمناسبة هي الـ Class Diagram عشان نوضح الـ Class اللي هنبنيها، وهنشرح الـ Diagram بالتفاصيل بعدين. وزي ما انت استنتجت دي خطوة من خطوات الـ OOD.
تعالى بقى نكتبه بالـ OOP..
class PositiveMathOperations
{
private uint Num1;
private uint Num2;
public uint GetNum1()
{
return this.Num1;
}
public uint GetNum2()
{
return this.Num2;
}
public void SetNum1(uint num)
{
if(num < 0) Console.WriteLine("Invalid input");
else this.Num1 = num;
}
public void SetNum2(uint num)
{
if(num < 0) Console.WriteLine("Invalid input");
else this.Num2 = num;
}
}
وكده حققنا الـ Encapsulation وطبعاً الـ Data Hiding اللي هي جزء من الـ Encapsulation .. عشان أذكرك بس، لما أقول Encapsulation يجي في بالك ان لما الـ Attributes والـ Methods تكون متجمعه مع بعض وبرده مفهوم الـ Data Hiding.
طب هو ده معناه إن كل الـ Attributes لازم تكون Private عشان أحافظ على مبدأ الـ Encapsulation؟
أيوة، عشان تخلي الكود بتاعك نظيف وMaintainable أو سهل الصيانة.. حافظ على المبدأ ده. لكن هل ده معناه انه مفيش ولا مرة في الدنيا هتلاقي الـ Attributes معموله public؟
- في حاجات ممكن تكون بسيطة جداً الـ Programmer ميعملهاش getter او setter زي ما عملنا GetNum1 وSetNum2 دي بنسميها getter وsetter بالمناسبه.. بس ده مازال بيكسر مبدأ الـ Encapsulation.
- في حاجه اسمها الـ DTOs (Data Transfer Objects) دي وظيفتها انها بتشيل الداتا من مكان لـ مكان تاني، بمعنى؟ “مش هتبطل بقى تسأل :”)"
بص تخيل معايا Class هنعمله دلوقتي اسمه Employee:-
class Employee
{
private int Id;
private string name;
private int age;
private string address;
private bool isOnline;
// .....
/// Some Business Logic here..
/// Implementating getters and setters
}
وطبع تخيل معايا أنه في Behaviors/Methods بتعمل شوية حاجاات على الداتا دي وطبعا عملنا الـ getters والـ setters.. دلوقتي انا عملت website والـ website ده فيه Form الـ Employee او الموظف ده هيدخل فيها بياناته.. لكن هنا الموظف غير معني او مش ملزم انه يشوف حاجه زي الـ Id
او زي الـ isOnline
وفي نفس الوقت انا مش عاوز استخدم الـ Employee Object ده عشان هيكون في بيانات الـ User مش معنى انه يشوفها أو مش مهم أو خطر أنها تتبعت فـ بنعمل DTO من الـ Employee ده فيه البيانات المهمة اللي هتتنقل بس من مكان لـ مكان، من الـ Frontend للـ Backend والعكس.
المهم،
دلوقتي الـ DTO دي احياناً في ناس بتعمل للـ Attributes بتاعتها public لأن مفيش فيها Logic بيشتغل على الـ Attributes دي.. بس برده فالحالة دي في ناس بتحافظ على المبدأ بتاع الـ Encapsulation ومش بتخليها public، لمجرد فقط أنها بتحافظ على المبدأ.
- في حالات نادرة أوي ليها علاقة بالـ Performance مش هنتكلم عنها دلوقتي.
- ببساطة، سوء تصميم.. ممكن تلاقي Attribute يكون public لمجرد اللي عمل الكود ده مش فاهم مبادئ الـ OOD.
النهاية
عاوزك تستوعب من الشرح ده حاجه مهمة جداً، الفرق ما بين الـ Class والـ Object.. الـ Class حاجه زي template وفيه rules والـ object ده بياخد نسخه من الـ template ده ويحافظ على الـ rules بتاعته.
فالأجزاء التانيه هنتكلم عن الـ Inheritance والـ Polymorphism والـ Composition.. فأبقوا معنا.