البرمجة كائنية التوجه، أو Object-Oriented Programming، هي نموذج برمجي كامل أساسه عن objects وclasses. هذا النموذج يحل مشاكل محددة يواجهها المطورون.
المشاكل التي يحلها:
Java هي من اللغات التي تدعم Object-Oriented Programming بشكل كامل. عندنا في هذا المجال أربعة مفاهيم أساسية، وكل واحد منها هو طريقة تفكير بحد ذاتها.
المبدأ بسيط: تحفظ الـ data اللي للكلاس وما تخلي أي أحد من الخارج يتحكم بها مباشرة.
فرضا عندك class اسمه BankAccount. هذا الـ class فيه property اسمها balance. أنت ما بتكون تخلي developers ثاني يروحوا يغيروا هالـ variable على كيفهم.
فكر فيها هيك: إذا كنت صاحب معمل آيس كريم، هل بتسمح لأي زبون يفوت جوا المصنع ويصنع بوزته بنفسه؟ لا، بيكون فيه كاشير، وهالكاشير هو اللي يعطيه الطلب على حسب ما طلب.
كيف نطبق هذا بالكود؟
أولا: تحدد الـ data لتكون private، يعني ما في أحد من خارج الكلاس يقدر يوصلها مباشرة.
ثانيا: تعطيهم methods محددة يتحكموا بالـ private data عن طريقها.
public class BankAccount {
private double balance = 0;
public double getBalance() {
return balance;
}
public void deposit(double amount) {
if (amount
اشترك في النشرة البريدية
دروس جديدة، مقالات، وأدوات مباشرة لبريدك.
الـ balance هنا private، يعني ما يصح أي شخص يعمل direct access عليها من خارج الكلاس.
الـ getBalance هي الطريقة الوحيدة لقراءة الرصيد. والـ deposit هي الطريقة الوحيدة لإضافة رصيد، وفيها شرط: المبلغ لازم يكون أكبر من صفر.
BankAccount account = new BankAccount();
account.deposit(100);
System.out.println(account.getBalance()); // 100.0
account.deposit(100);
account.deposit(100);
System.out.println(account.getBalance()); // 300.0هيك صار عندنا تحكم كامل بالـ balance. فكرة كثير بسيطة.
الـ Inheritance أو الوراثة تحل مشكلة التكرار بين كلاسات مترابطة مع بعض.
تخيل عندك كلاسات للحيوانات: Cat وDog. كلاهما حيوانات، وعندهم صفات مشتركة:
| الصفة المشتركة | النوع |
|---|---|
name | String |
age | int |
eat() | method |
لو كتبنا هالصفات بكل كلاس على حدة، بنكرر نفس الكود مرتين. الحل هوننشئ parent class مشترك.
أولا: نبني الـ parent class اللي فيه الصفات المشتركة:
public class Animal {
public String name;
public int age;
public Animal(String name, int age) {
this.name = name;
this.age = age;
}
public void eat() {
System.out.println("eating...");
}
}ثانيا: نبني الـ child classes باستخدام الكلمة extends:
public class Cat extends Animal {
public Cat(String name, int age) {
super(name, age);
}
public void makeSound() {
System.out.println("Meow");
}
}الكلمة extends تعني إننا رح نورث كل شي public موجود بالـ Animal.
الـ super هي function خاصة وظيفتها تنقل الـ data للـ parent class. فكر فيها كباص ينقل الناس من مكان لآخر، نفس الشي الـ super ينقل الـ data للـ constructor اللي فوقه.
Cat cat = new Cat("Whiskers", 3);
System.out.println(cat.name); // Whiskers
System.out.println(cat.age); // 3
cat.eat(); // eating...الـ name والـ age ما موجودين بالـ Cat مباشرة، بس وصلوا إليها عن طريق الوراثة من الـ Animal.
الـ Polymorphism أو تعدد الأشكال يعني إننا نقدر نستخدم نفس اسم الـ method بطرق مختلفة.
Override: إذا كان عندنا makeSound بالـ Animal، كل حيوان يقدر يحط implementation خاصة فيه.
public class Animal {
public void makeSound() {
System.out.println("making sound...");
}
}
public class Dog extends Animal {
@Override
public void makeSound() {
System.out.println("Woof");
}
}
public class Cat extends Animal {
@Override
public void makeSound() {
System.out.println("Meow");
}
}الكلمة @Override تعني إننا عم نغير implementation الـ method اللي ورثناها من الـ parent.
Overloading: نقدر كمان نعمل نفس اسم الـ method بنفس الكلاس، بس بـ parameters مختلفة.
public class Calculator {
public int sum(int a, int b) {
return a + b;
}
public int sum(int a, int b, int c) {
return a + b + c;
}
}Calculator calc = new Calculator();
System.out.println(calc.sum(1, 2)); // 3
System.out.println(calc.sum(1, 2, 3)); // 6Java بتميز أي function تشغلها على حسب عدد الـ arguments. أول call فيه اثنين arguments فاخذ أول implementation، وثاني call فيه ثلاثة arguments فاخذ ثاني implementation.
الـ Abstraction هو إخفاء التفاصيل المعقدة وإظهار بس الواجهة البسيطة للمستخدم.
فكر بالسيارة: جواتها محرك، وصلات، fuel system، كلهم مخبيين جواتها. المستخدم ما يحتاج يعرف كيف تشتغل هالأشياء. عنده بس:
اليوزر عنده interface بسيطة، والتعقيد مخبي جواتها.
بالكود هو شي بسيط: أي function عادية هي abstraction بحد ذاتها.
public class Animal {
public void makeSound() {
// complex logic here
// the caller doesn't need to know how it works
System.out.println("making sound...");
}
}المستخدم أو الـ developer ما يحتاج يعرف شو هو الـ complex logic جوا، كل اللي عليه إنه يستدعي makeSound وبس.
الـ Inheritance مفيد، بس ما ينصح بيه بشكل مبالغ فيه. مشكلته تظهر لما تبدأ تعمل أكثر من level.
إذا عندك:
Animal → Cat → PersianCat
هذا صار عندك level ثاني من الوراثة. كل ما زادت الـ levels، صار التعامل مع الكود أصعب وأكثر تعقيدا. بعض اللغات ما بتسمح أكثر من level واحد.
الـ Composition هو البديل الأفضل. الفرق بالتفكير:
| الطريقة | طريقة التفكير |
|---|---|
| Inheritance | Honda is a Car |
| Composition | Honda has an Engine |
مثال عملي:
public class Engine {
public void start() {
System.out.println("Engine started");
}
}
public class Car {
private Engine engine;
public Car() {
this.engine = new Engine();
}
public void startCar() {
engine.start();
}
}الـ engine هنا private variable من نوع Engine. بالـ constructor نعمل new Engine() وتحفظه بالـ variable. وعن طريق method معينة زي startCar نقدر نوصل لـ methods الـ Engine.
هيكذا الـ Car عندها engine بدون ما ترث منه، وهذا أوضح وأسهل في التعامل.
هذا كان مقدمة للـ Object-Oriented Programming. لسا عم نخدش السطح، وفي كثير مفاهيم ستتفاجأوا فيها في الفيديوهات الجاية.