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

בג'אווה, למופע של מחלקה A יש שדה f ומתודה getF() המחזירה עותק שטחי (shallow copy) של f. באילו מן התרחישים הבאים getF() בוודאות אינה חושפת את A לשינויים מבחוץ של המצב הפנימי שלו (כלומר, שינויים שלא דרך פקודות של A)?

1. אם השדה f מוגדר כ-final
2. אם השדה f הוא מטיפוס ממשק

3. אם השדה f הוא מטיפוס סטטי

4. אם השדה f הוא מטיפוס פרימיטיבי

5. אם A מוגדרת כ-final
העתק שאלה
שתף שאלה
סמן כחשוב
סמן כבוצע
אוניברסיטת בר-אילןמועד א2019סמסטר ב
הסתרת מידעאובייקטיםמחלקות
חשבו על ההבדל הבסיסי בין טיפוסים פרימיטיביים (המועברים by-value) לבין אובייקטים (שהגישה אליהם היא דרך רפרנס) בג'אווה. מתי החזרת עותק אינה מאפשרת גישה למקור?
התשובה הנכונה היא 4. המטרה של הסתרת מידע (encapsulation) היא להגן על המצב הפנימי של אובייקט מפני שינויים חיצוניים בלתי מבוקרים. מתודת getter שנועדה לספק גישה למידע עלולה להפר עיקרון זה אם היא חושפת רפרנס (הפניה) לשדה פנימי שהוא mutable (בר-שינוי).

כאשר מתודה מחזירה "עותק שטחי" של שדה שהוא אובייקט, היא למעשה מחזירה עותק של הרפרנס, המצביע לאותו האובייקט המקורי בזיכרון. אם האובייקט הזה הוא mutable, הקוד שקיבל את הרפרנס יכול להשתמש בו כדי לשנות את מצבו הפנימי של האובייקט, ובכך לשנות את המצב הפנימי של מופע המחלקה A, מבלי להשתמש במתודות של A.


נבחן את האפשרויות:


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


2. אם השדה `f` הוא מטיפוס ממשק: ממשק מגדיר חוזה אך אינו מבטיח שהמימוש הקונקרטי יהיה immutable (לא בר-שינוי). לדוגמה, השדה יכול להיות מהטיפוס List (ממשק) והאובייקט בפועל יהיה ArrayList, שהוא mutable.


3. אם השדה `f` הוא מטיפוס סטטי: המילה השמורה static הופכת את השדה למשתנה מחלקה המשותף לכל המופעים, ולא למשתנה ספציפי למופע. אין לכך קשר לשאלת ה-mutability. החזרת רפרנס לשדה סטטי שהוא mutable עדיין חושפת אותו לשינויים שישפיעו על כל המופעים.


4. אם השדה `f` הוא מטיפוס פרימיטיבי: זו התשובה הנכונה. טיפוסים פרימיטיביים בג'אווה (int, double, boolean וכו') אינם אובייקטים ומועברים תמיד by value (לפי ערך). כאשר המתודה getF מחזירה את הערך של f, היא מחזירה עותק של הערך עצמו. אין שום דרך שבה הקוד הקורא יוכל להשתמש בעותק זה כדי לשנות את הערך המקורי של השדה f בתוך האובייקט. לכן, במקרה זה, המצב הפנימי מוגן לחלוטין.


5. אם A מוגדרת כ-`final`: הגדרת המחלקה A כ-final מונעת יצירת תת-מחלקות שלה (כלומר, מונעת ירושה). אין לכך כל השפעה על ה-mutability של השדות שלה או על האופן שבו רפרנסים אליהם מוחזרים.