מחלקות פנימיות, מקוננות ואנונימיות
חלק מהיחידה תכנות מונחה עצמים במסלול ה-Java של Coddy. שיעור 49 מתוך 87.
ב-Java אפשר להגדיר מחלקות בתוך מחלקות אחרות. מחלקות פנימיות עוזרות לארגן את הקוד על ידי קיבוץ פונקציונליות קשורה, ויכולות לגשת ישירות לחברים של המחלקה החיצונית.
מחלקה פנימית מקוננת מוגדרת כחברה במחלקה אחרת. יש לה גישה לכל השדות והמתודות של המחלקה החיצונית, כולל הפרטיים:
class Outer {
private String message = "Hello";
class Inner {
void display() {
System.out.println(message); // יכולה לגשת לשדה פרטי
}
}
}
// שימוש
Outer outer = new Outer();
Outer.Inner inner = outer.new Inner();
inner.display(); // מדפיסה: Helloמחלקה פנימית מקומית מוגדרת בתוך מתודה. ניתן להשתמש בה רק בתוך אותה מתודה, והיא יכולה לגשת למשתנים מקומיים שהם למעשה סופיים:
void process() {
String prefix = "Result: ";
class LocalHelper {
void print(int value) {
System.out.println(prefix + value);
}
}
new LocalHelper().print(42);
}מחלקה פנימית אנונימית היא מחלקה ללא שם, שנוצרת ומופע שלה נוצר בביטוי אחד. משתמשים בה בדרך כלל כדי לממש ממשקים או להרחיב מחלקות תוך כדי כתיבה:
Comparator<String> comp = new Comparator<String>() {
@Override
public int compare(String a, String b) {
return a.length() - b.length();
}
};מחלקות פנימיות שימושיות במיוחד כאשר מחלקה רלוונטית רק למחלקה אחרת אחת, וכך הקוד שלך נשאר מאורגן ומכומס.
אתגר
קלבואו נבנה מערכת של עגלת קניות שמדגימה את כל שלושת הסוגים של מחלקות פנימיות. תיצרו ShoppingCart שתשתמש במחלקה פנימית מקוננת כדי לייצג פריטים, במחלקה פנימית מקומית כדי לחשב הנחות, ובמחלקה פנימית אנונימית כדי לעצב את הקבלה הסופית.
תארגנו את הקוד שלכם בשני קבצים:
ShoppingCart.java: צרו את המחלקה החיצונית שמנהלת את חוויית הקנייה. ל- ShoppingCart שלכם צריך להיות שדה פרטיcustomerName(String).בתוך ShoppingCart, הגדירו מחלקה פנימית מקוננת בשם
Itemעם שני שדות פרטיים:name(String) ו-price(double). הוסיפו ל-Item בנאי שיאתחל את שני השדות ומתודהgetDetails()שמחזירה:[name]: $[price]ל- ShoppingCart שלכם דרוש בנאי שמקבל את שם הלקוח, ומתודה בשם
checkout()שמקבלת Item ואחוז הנחה (double). בתוךcheckout():- צרו מחלקה פנימית מקומית בשם
DiscountCalculatorעם מתודהapplyDiscount(double originalPrice)שמחזירה את המחיר לאחר החלת אחוז ההנחה. - השתמשו במחלקה המקומית כדי לחשב את המחיר הסופי.
- צרו מחלקה פנימית אנונימית שמממשת את הממשק
Formatter(אתם תגדירו אותו) כדי לעצב את הקבלה. המחלקה האנונימית צריכה לדרוס מתודהformat()שמחזירה מחרוזת קבלה מרובת שורות.
המתודה
checkout()צריכה להחזיר את מחרוזת הקבלה המעוצבת בפורמט המדויק הבא:--- Receipt --- Customer: [customerName] Item: [item details from getDetails()] Discount: [discount]% Final Price: $[calculated price]- צרו מחלקה פנימית מקומית בשם
Formatter.java: הגדירו ממשק פשוט עם מתודה יחידה:String format(). הממשק הזה ימומש על ידי המחלקה הפנימית האנונימית שלכם בתוך מתודת checkout.Main.java: הפיחו חיים בעגלת הקניות שלכם! תקבלו שלוש קלטים: שם הלקוח (String), שם הפריט (String) ומחיר הפריט (double). אחוז ההנחה קבוע על10.0.צרו ShoppingCart עם שם הלקוח. לאחר מכן צרו Item באמצעות תחביר ההפניה למחלקה החיצונית:
cart.new Item(name, price). קראו ל-checkout()עם הפריט וההנחה, והדפיסו את הקבלה שהוחזרה.
תקבלו שלוש קלטים לפי הסדר: שם הלקוח, שם הפריט ומחיר הפריט.
לדוגמה, אם הקלטים הם Alice, Laptop ו-1000.0, המחיר הסופי לאחר הנחה של 10% יהיה 900.0.
שימו לב כיצד כל סוג של מחלקה פנימית משרת מטרה אחרת: המחלקה המקוננת מקבצת נתונים קשורים עם המחלקה החיצונית, המחלקה המקומית מכילה לוגיקה שנדרשת רק בתוך מתודה אחת, והמחלקה האנונימית מספקת מימוש מהיר וחד-פעמי של ממשק!
נסו בעצמכם
import java.util.Scanner;
class Main {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
// קראו את הקלט
String customerName = scanner.nextLine();
String itemName = scanner.nextLine();
double itemPrice = scanner.nextDouble();
double discount = 10.0;
// TODO: צרו ShoppingCart עם שם הלקוח
// TODO: צרו Item באמצעות: cart.new Item(itemName, itemPrice)
// TODO: קראו ל־checkout() עם הפריט וההנחה, ואז הדפיסו את התוצאה
}
}
השיעור הזה כולל חידון קצר. התחילו את השיעור כדי לענות עליו ולעקוב אחרי ההתקדמות.
כל השיעורים ביחידה תכנות מונחה עצמים
1יסודות התכנות מונחה העצמים
קבצים חיצונייםמבוא לתכנות מונחה עצמיםמחלקות לעומת אובייקטיםמילת המפתח thisמתודותשדות (מאפיינים)מתודת הבנאיהעמסת בנאיםחזרה – מחשבון פשוט4ירושה
ירושה בסיסית (extends)מילת המפתח superדריסת מתודות (@Override)שרשור בנאיםהמחלקה Objectירושה יחידה ורב־רמתיתלמה אין ירושה מרובה של מחלקותסיכום – היררכיית עובדים7מתודות מיוחדות ומחלקת Object
מתודת toString()equals() ו-hashCode()מתודת clone()compareTo() ו-Comparableהממשק Comparatorסיכום – מיון מותאם אישית2מצייני גישה ואנקפסולציה
סקירה של רמות הגישהמתודות Getter ו-Setterהסתרת מידעמילת המפתח finalסיכום – מנהל חשבון בנק5פולימורפיזם
יסודות העמסת מתודותדריסת מתודות (בזמן ריצה)המרה כלפי מעלה וכלפי מטההאופרטור instanceofמחלקות ומתודות מופשטותסיכום – מחשבון צורות8מושגי OOP מתקדמים
הרכבה מול ירושהאגרגציה מול הרכבהמחלקות פנימיות, מקוננות ואנונימיותEnums ומתודות של EnumRecords (Java 16+)מחלקות חתומות (Java 17+)3מאפייני מחלקה וחברים סטטיים
משתני מופע לעומת משתנים סטטייםמתודות סטטיותבלוקים סטטייםקבועים (static final)סיכום — מונה ומחלקת עזר6ממשקים ומחלקות מופשטות
מבוא לממשקיםמימוש ממשקיםמימוש של כמה ממשקיםמתודות ברירת מחדל וסטטיות בממשקמחלקות מופשטות לעומת ממשקיםממשקים פונקציונלייםסיכום – מערכת תשלומיםתרגלו בעצמכם: קומפיילר Java אונליין