שאלת מבחן בתכנות מונחה עצמים - אוניברסיטת בר-אילן 2024 - מחלקות

נתונות מחלקות הבאות:



משה, סטודנט בקורס תכנות מונחה עצמים, רוצה להפוך את המחלקה B ל-immutable, ומציע לעשות את זה בדרך הבאה:




האם הפתרון של משה נכון?


א. כן


ב. לא


ג. בבנאי לא מופעל clone
העתק שאלה
שתף שאלה
סמן כחשוב
סמן כבוצע
אוניברסיטת בר-אילןמועד א2024סמסטר ב
מחלקותאובייקטיםקונסטרוקטורהסתרת מידעמעקב אחר קודImmutability
חשבו מה קורה אם לאחר יצירת אובייקט ImmB, הקוד החיצוני משנה את האובייקט מסוג A שהועבר במקור לבנאי שלו.
הפתרון של משה אינו נכון. לכן, התשובה הנכונה היא ב'. הסיבה לכך היא שהבנאי אינו מבצע העתקה הגנתית של האובייקט שהוא מקבל, כפי שמצוין בתשובה ג'.

אובייקט בלתי-משתנה (Immutable) הוא אובייקט שמצבו הפנימי אינו יכול להשתנות לאחר יצירתו. כדי להבטיח זאת, יש להקפיד על מספר כללים:
1. יש למנוע שינוי של שדות האובייקט לאחר היצירה (בדרך כלל על ידי הגדרתם כ-final).

2. יש למנוע מלקוח חיצוני לקבל רפרנס ישיר לאובייקטים פנימיים שהם בני-שינוי (mutable).

3. יש למנוע מלקוח חיצוני להעביר לבנאי רפרנס לאובייקט בן-שינוי שיישמר ישירות בתוך האובייקט שלנו.


הפתרון של משה אכן מטפל בכלל מספר 2 על ידי החזרת עותק במתודה get(), וכן מצהיר על השדה a כ-final. עם זאת, הוא נכשל בכלל מספר 3.


הבעיה המרכזית נמצאת בבנאי (constructor) של המחלקה ImmB:

הבנאי מקבל הפניה (reference) לאובייקט A ושומר אותה בשדה הפנימי this.a. מכיוון שהמחלקה A היא בת-שינוי (mutable) (יש לה את המתודה setX), קוד חיצוני יכול לשנות את מצבו של האובייקט a שהועבר לבנאי *לאחר* יצירת האובייקט ImmB, ובכך לשנות בפועל את המצב הפנימי של ImmB. הדבר שובר את עקרון אי-השינוי.


לדוגמה, הקוד הבא מדגים כיצד ניתן לשנות את המצב של ImmB:


הפתרון הנכון דורש יצירת עותק הגנתי (defensive copy) של האובייקט a בתוך הבנאי, כדי לנתק את הקשר בין האובייקט הפנימי לאובייקט שהתקבל מבחוץ. הבנאי המתוקן צריך להיראות כך:

כך, כל שינוי עתידי באובייקט a המקורי לא ישפיע על המצב הפנימי של האובייקט ImmB שנוצר.