📘 JavaScript - מדריך
לימוד שלב אחר שלב עם ניווט צד ופרקים נפרדים.
💡 OOP - תכנות מונחה עצמים
📘 תוכן עניינים:
מה זה OOP?
תכנות מונחה עצמים (OOP) הוא סגנון תכנות שבו אנחנו מחלקים את הקוד ליחידות הנקראות "אובייקטים". כל אובייקט מייצג ישות מהעולם האמיתי – לדוגמה: רכב, תלמיד, מוצר.
כל אובייקט מורכב מ:
- משתנים (fields): מאפיינים של האובייקט, כמו שם, מחיר, צבע.
- שיטות (methods): פעולות שהאובייקט יכול לבצע.
היתרון של OOP הוא שהוא מסדר את הקוד בצורה ברורה ומאפשר לנו לכתוב תוכניות מורכבות שקל להבין ולתחזק. זה גם מאפשר שימוש חוזר בקוד והרחבה של פונקציונליות בקלות רבה.
public class Car {
String make;
int year;
void drive() {
System.out.println("Driving...");
}
}
פלט: Driving...
1. Constructor
בנאי (Constructor) הוא שיטה מיוחדת שנקראת אוטומטית כאשר נוצר אובייקט חדש מתוך מחלקה. מטרת הבנאי היא לאתחל את ערכי האובייקט בעת יצירתו. הבנאי עוזר לכתוב קוד ברור, מסודר וקצר יותר.
כאשר אנחנו יוצרים אובייקט ללא בנאי – נצטרך להכניס כל ערך של שדה בנפרד. זה עלול להיות מייגע כאשר יש הרבה שדות.
לעומת זאת, כאשר יש בנאי – ניתן להכניס את כל הערכים במכה אחת, כבר בזמן יצירת האובייקט.
Car toyota = new Car();
toyota.make = "Toyota";
toyota.price = 10000;
toyota.year = 2020;
toyota.color = "Green";
פלט: אין פלט – רק הגדרת ערכים לאובייקט.
Car toyota = new Car("Toyota", 10000, 2020, "Green");
פלט: אין פלט – ערכים הוגדרו בבנאי.
public class Car {
String make;
int price;
int year;
String color;
public Car(String make, int price, int year, String color) {
this.make = make;
this.price = price;
this.year = year;
this.color = color;
}
}
פלט: אין פלט – המחלקה רק מגדירה את הבנאי.
🔧 הקשר בין OOP לאוטומציה בתכנות
תכנות מונחה עצמים (OOP) הוא הבסיס לפיתוח מערכות חכמות שמבצעות משימות באופן אוטומטי, ללא צורך בהתערבות ידנית. בעזרת יצירת מחלקות שמייצגות אובייקטים מהעולם האמיתי, אנחנו יכולים לתכנן מערכות גמישות, מודולריות וניתנות להרחבה.
אוטומציה בתכנות פירושה שהמחשב מבצע פעולות באופן עצמאי על פי לוגיקה שהוגדרה מראש. למשל: סידור רשימות, ניתוח מידע, מענה חכם לפעולות משתמש, או ניהול חפצים בעולם וירטואלי. השילוב של OOP עם אוטומציה מאפשר לנו לבנות קוד שמבצע בעצמו חישובים, בודק תנאים, מחליט החלטות – ומתקדם קדימה בלי שנצטרך לכתוב שוב ושוב את אותן פעולות.
בקיצור: OOP הוא הכלי, ואוטומציה היא המטרה – ליצור תוכנות שמתפקדות בעצמן, בדיוק כמו רובוטים דיגיטליים שחיים בתוך הקוד.
🧠 שאלות לדוגמה:
שאלה 1: הכבשה דולי 🐑
צור מחלקה בשם Dolly
בשפת Java, שמייצגת כבשה. המחלקה תכיל שדות כמו שם, גזע, משקל, גובה וכמות חלב ליום. הוסף בנאי (Constructor), פעולות get ו־set לכל שדה, ופעולה המחזירה את ערך ה־BMI של הכבשה. חשוב מאוד להוסיף הערות בתוך הקוד כדי להסביר מה עושה כל שדה או פעולה – כך תבין איך עובד תכנות מונחה עצמים (OOP).
🔍 הסבר עקרוני על OOP:
תכנות מונחה עצמים הוא סגנון תכנות שבו אנחנו יוצרים מחלקות (Classes) שמייצגות ישויות מהעולם האמיתי – כמו כבשה, תלמיד, רכב או ספר. כל מחלקה מכילה שדות (משתנים), ושיטות (פעולות/פונקציות) שמאפשרות לבצע דברים עם האובייקט. באמצעות בנאי אנחנו יכולים ליצור אובייקט חדש עם ערכים מוגדרים, ודרך Setters ו־Getters אפשר לשנות ולקרוא את הערכים. מחלקות בשפת Java הן הבסיס לכל פרויקט רציני בתכנות – במיוחד כשאנחנו רוצים שהקוד יהיה מסודר, גמיש, וניתן להרחבה. עבודה עם מחלקות ו־OOP חשובה גם כשנרצה לעבור לשפות נוספות כמו Python או ++C, שכן העקרונות דומים.
🧩 מחלקת Dolly עם הערות:
// מחלקה שמייצגת כבשה
public class Dolly {
// שדות (fields) - מאפיינים של הכבשה
private String name; // שם הכבשה
private String typeName; // גזע
private int weight; // משקל בק"ג
private int height; // גובה בס"מ
private int milkWeight; // משקל חלב ליום
// בנאי (Constructor) - מאתחל את כל השדות
public Dolly(String name, String typeName, int weight, int height, int milkWeight) {
this.name = name;
this.typeName = typeName;
this.weight = weight;
this.height = height;
this.milkWeight = milkWeight;
}
// גטטרים (Getters) - מחזירים ערכים של שדות
public String getName() { return name; }
public String getTypeName() { return typeName; }
public int getWeight() { return weight; }
public int getHeight() { return height; }
public int getMilkWeight() { return milkWeight; }
// סטטרים (Setters) - מאפשרים לעדכן ערכים
public void setName(String name) { this.name = name; }
public void setTypeName(String typeName) { this.typeName = typeName; }
public void setWeight(int weight) { this.weight = weight; }
public void setHeight(int height) { this.height = height; }
public void setMilkWeight(int milkWeight) { this.milkWeight = milkWeight; }
// פעולה שמחשבת את ה-BMI של הכבשה
public double calculateBMI() {
double heightInMeters = height / 100.0;
return weight / (heightInMeters * heightInMeters);
}
}
💻 שימוש במחלקה והדפסת BMI:
public class Main {
public static void main(String[] args) {
Dolly dolly = new Dolly("דולי", "כבשה ישראלית", 60, 120, 5);
System.out.println("שם: " + dolly.getName());
System.out.println("BMI: " + dolly.calculateBMI());
}
}
// פלט:
// שם: דולי
// BMI: 41.666...
שים לב: מדד BMI עוזר לבדוק האם המשקל של הכבשה תקין יחסית לגובה שלה. שיטה זו שימושית גם באובייקטים אחרים שמכילים מידע כמותי ויחסי. תרגול זה מדגים כיצד לשלב בין מידע (שדות) לפעולה (חישוב).
שאלה 4: תכנון מערכת לניהול חוות סוסים 🐴
בחוות סוסים וירטואלית נדרש לתכנן מערכת מונחית עצמים שמנהלת את הסוסים, הבעלים והחווה עצמה. לפניך הגדרות המחלקות הראשיות:
📦 הגדרת המחלקות ההתחלתית:
// מחלקה שמייצגת אדם – עם שם ומספר מזהה
public class Person {
private String _name;
private String _id;
...
}
// מחלקה שמייצגת סוס – עם בעלים, האם הוא חד־קרן, ואורך זנב
public class Horse {
private Person _owner;
private boolean _isUnicorn;
private double _tail;
...
}
// מחלקה שמייצגת חווה שמכילה מערך של סוסים
public class Farm {
final int MAX = 100;
private Horse[] _horses;
private int _current;
public Farm() {
_horses = new Horse[MAX];
_current = 0;
}
}
🧩 סעיף א': בנאי למחלקת Horse
כתוב בנאי שמקבל בעלים ואורך זנב. אם הזנב קטן מ־0, הגדר אותו כ־1. אם הבעלים הוא חד־קרן – הפוך גם את הסוס לחד־קרן. אחרת, הסוס אינו חד־קרן. פעולה זו מדגימה קבלת פרמטרים, בדיקות תנאי, והקצאת ערכים לשדות מתוך בנאי – בסיס חשוב ב־OOP.
public Horse(Person owner, double tail) {
if (tail < 0) tail = 1;
this._owner = owner;
this._tail = tail;
if (owner != null && owner.isUnicorn())
_isUnicorn = true;
else
_isUnicorn = false;
}
🧩 סעיף ב': השוואת אורך זנבות בין סוסים
כתוב פעולה שמקבלת סוס אחר, ומשווה את אורך הזנב של הסוס הנוכחי לזה של הסוס שנשלח כפרמטר. אם של הסוס הנוכחי גדול – נחזיר 1. אם של השני גדול – נחזיר -1. אם זהים – נחזיר 0. השוואה זו מאפשרת סידור, מיון והשוואה בין אובייקטים לפי שדה מספרי.
public int compareTail(Horse other) {
if (this._tail > other._tail) return 1;
else if (this._tail < other._tail) return -1;
else return 0;
}
🧩 סעיף ג': ממוצע אורך זנבות
כתוב פעולה במחלקת Farm שמחזירה את ממוצע אורך הזנבות של כל הסוסים הקיימים. אם אין סוסים, נחזיר 0. הפעולה מדגימה שימוש בלולאה, חישוב מצטבר וחלוקה במספר פריטים.
public double tailAverage() {
if (_current <= 0) return 0;
double sum = 0;
for (int i = 0; i < _current; i++) {
sum += _horses[i].getTail();
}
return sum / _current;
}
🧩 סעיף ד': הוספת סוס למערך לפי סדר
כתוב פעולה שמוסיפה סוס למערך לפי סדר עולה של אורך זנב. תחילה נבדוק אם יש מקום פנוי. לאחר מכן נמצא את המיקום הנכון באמצעות לולאת while, נזיז את הסוסים האחרים ימינה בלולאת for, ונדביק את הסוס החדש במיקום המתאים.
public boolean addHorse(Horse b) {
if (_current >= MAX) return false;
int i = 0;
while (i < _current && b.getTail() > _horses[i].getTail()) {
i++;
}
for (int j = _current; j > i; j--) {
_horses[j] = _horses[j - 1];
}
_horses[i] = b;
_current++;
return true;
}
🧩 סעיף ה': מציאת הבעלים של הסוס עם הזנב הארוך ביותר
כתוב פעולה שמחזירה את הבעלים של הסוס עם אורך הזנב הגדול ביותר. נשתמש בערך מקסימום זמני ונתקן אותו כל פעם שנמצא סוס עם זנב ארוך יותר. חשוב לוודא שהתוצאה היא מסוג Person
.
public Person maxTailOwner() {
- קודם נרשום את התנאי הראשון שאם אין סוסים בחווה נחזיר null //
if (_current <= 0) return null;
- הוספת משתנים בשביל שיהיה עם מה לחשב //
double maxTail = _horses[0].getTail();
Person maxOwner = _horses[0].getOwner();
- לואלה שעוברת על כל הרשימת סוסים
for (int i = 1; i < _current; i++) {
- תנאי - שאם הזנב של הסוס מהאינדקס הראשון ברשימה גדול מהזנב הכי ארוך
- אז הזנב שלו יהיה הכי גדול וכך הלולאה חוזרת על עצמה
if (_horses[i].getTail() > maxTail) {
maxTail = _horses[i].getTail();
- ואחרי שאנחנו יודעים לאיזה סוס יש את הזנב הכי ארוך נשייך אותו לבעלים
maxOwner = _horses[i].getOwner();
}
}
return maxOwner;
}
סעיפים אלו מדגימים בצורה פרקטית עקרונות מרכזיים ב־OOP: יצירת מחלקות, עבודה עם אובייקטים, שימוש בשדות ובפעולות, שמירה על סדר בתוך מערך, חישובים וניתוח מידע.
שאלה 3: פעולה במחלקת Line 📏
כתוב מחלקת Point
המייצגת נקודה במישור XY עם שדות x ו־y, פעולה בונה ו־toString. כתוב מחלקת Line
עם פעולות למציאת אורך, בדיקה אם הקו אופקי או אנכי, ותיאור.
💡 הסבר חשוב: בגלל ש-x ו-y הם private, ניגשים אליהם באמצעות getX ו-getY לפי עקרונות OOP (כמוסה).
📍 מחלקת Point:
// מחלקת Point מייצגת נקודה דו-ממדית עם שדות x ו-y.
public class Point {
private double x;
private double y;
// פעולה בונה שמאתחלת את ערכי x ו-y
public Point(double x, double y) {
this.x = x;
this.y = y;
}
// פעולות גישה לשדות — לפי עקרון Encapsulation
public double getX() { return x; }
public double getY() { return y; }
// מייצרת תיאור טקסטואלי של נקודה
public String toString() {
return "(" + x + ", " + y + ")";
}
}
📏 מחלקת Line:
public class Line {
private Point start;
private Point end;
// פעולה בונה שמקבלת שתי נקודות
public Line(Point start, Point end) {
this.start = start;
this.end = end;
}
// מחשבת את אורך הקו לפי נוסחת פיתגורס
public double length() {
double dx = end.getX() - start.getX();
double dy = end.getY() - start.getY();
return Math.sqrt(dx * dx + dy * dy);
}
// בודקת אם הקו אופקי (אותו ערך Y)
public boolean isHorizontal() {
return start.getY() == end.getY();
}
// בודקת אם הקו אנכי (אותו ערך X)
public boolean isVertical() {
return start.getX() == end.getX();
}
// מייצרת תיאור טקסטואלי של הקו
public String toString() {
return "Line from " + start + " to " + end;
}
}
🧪 דוגמה להרצה (Main):
public class Main {
public static void main(String[] args) {
Point a = new Point(2, 3);
Point b = new Point(6, 8);
Line line = new Line(a, b);
System.out.println("אורך הקו: " + line.length());
System.out.println("האם אופקי? " + line.isHorizontal());
System.out.println("האם אנכי? " + line.isVertical());
System.out.println("תיאור: " + line);
}
}