שאלה בעניין data encapsulation ו- get methods – ב(java)

YIM222

New member
שאלה בעניין data encapsulation ו- get methods – ב(java)

- עד היום הבנתי שהדרך הנכונה היא לעשות את הfields private ולעשות return לfield ע"י getField. ו return field.
בשאלה הבאה (מתוך מבחן הסמכה של oracle) (ראה תמונות) נראה שזה לא ממש נכון. ההתלבטות היא בין תשובה 3 ל-4 וכמו שרואים בתשובה הם אומרים שהנכון הוא 4. אז באמת ככה צריך לעשות getMethod?עם .clone(); ? או שזה משהו אחר בגלל שזה array?

תודה מראש



 

BravoMan

Active member
זה תלוי בסוג השדה!

הראיון ב-encapsulation הוא למנוע שינוי של מידע פנימי של אובייקט מחוץ לאובייקט.
אם השדה הוא public, כל אחד יכול לעשות בו מה שרוצים.
&nbsp
אבל אם השדה הוא private, זה כבר תלוי מה יש בו:
אם השדה הוא טיפוס פרימיטיב (int, char, boolean) או אובייקט immutable כמו String אפשר פשוט להחזיר אותו, כי אין סיכוי שישנו אותו בחוץ.
אבל אם השדה הוא אובייקט בר שינוי (mutable), כמו מערך, הרי שברגע שהוצאת אותו החוצה, כל אחד יכול לשנות את התוכן שלו.
זכור, שעבור כל טיפוס שאינו פרימיטיבי, שדות ומשתנים ב-Java מחזיקים למעשה reference.
&nbsp
בשאלת הדוגמה, אם תחזיר את המערך המקורי, בלי clone, למעשה תחזיר רפרנס למערך, וכך כל אחד יוכל לשחק עם האיברים שלו מחוץ למחלקה Pedometer בלי שהמלחקה "תדע" מזה.
המערך בחוץ יהיה אותו מערך שבפנים, וכל שינוי בו יהיה שינוי בתוך האובייקט, מה שכאמור ישבור את ה-encapsulation.
 

YIM222

New member
תודה.. אז בעצם כך ננהג כשנעשה return ל array.... או לobject

אתה יכול להסביר לי בדיוק מה הכוונה reference? קראתי על זה והבנתי שזה שלא כמו primitive data אבל לא הבנתי מה ההבדל המהותי...
 

BravoMan

Active member
אתה יכול לחשוב על זה כמו "כתובת" של אובייקט:

reference - נותן לך בעצם גישה לאובייקט עצמו: המשתנה מכיל רק איזה מספר - או כתובת, לא את הנתונים עצמם, אבל דרכו אתה יכול לגשת למקום בו הנתונים של האובייקט מאוחסנים.
&nbsp
העניין הוא, שכל מי שיש לו את הכתובת הזו, יכול לגשת ולשנות את הנתונים של האובייקט.
&nbsp
נניח שיש לך משתנה פרימיטיב מסוג int שקוראים לו var שמכיל 5.
כשאתה שולח אותו לפונקציה, מה שנשלח זה למעשה המספר 5 - הנתון, או עותק של תוכן המשנה.
&nbsp
לא משנה מה מישהו יעשה עם ה-5 הזה. הוא לא באמת קשור ל-var, ואין דרך להשפיע על var דרכו.
&nbsp
עכשיו, נניח שיש לך משתנה arr שהוא מערך.
המשתנה הזה לא באמת שומר את כל איברי המערך בתוכו. מה שהוא שומר, דומה לכתובת בזיכרון בה שמורים האיברים (אני לא התעמקתי במימוש המדויק של Java).
כשאתה "נותן" את הכתובת הזו לפוקנציה, היא יכולה להתשמש בה כדי לגשת לאותו זיכרון, ולשנות את האיברים עצמם.
תוכן arr לא ישתנה - הוא עדיין יחזיק את אותה הכתובת, אבל מה שנמצא בכתובת - הנתונים, ישתנו.
&nbsp
מערך, הוא למעשה סוג של אובייקט ב-Java, והתיאור הזה נכון לכל אובייקט.
&nbsp
מקווה שזה הסבר פשטתני מספיק...
 

YIM222

New member
עדיין לא הבנתי

ניסיתי לעשות class גם עם array וגם עם object .

1- אם הarray הוא private אין לי אפשרות לשנות או לעשות לו איתחול או whatever רק לערך שלו.

2- לגבי object אם זה object שבנוי נכון אז יהיה גישה רק למה שpublic אצלו כמו שיוצרים בעולם object אז אם יש גישה למה זה בסדר שיהיה גישה אז מה הבעיה.....
 

BravoMan

Active member
בלי לראות מה ניסית לעשות, אי אפשר להבין כ"כ את השאלה.

מה יצרת?
&nbsp
מה זה "בסדר" מול "לא בסדר"?
&nbsp
למה לדעתך יש גישה?
למה לדעתך אין גישה?
למה אתה רוצה שתהיה גישה?
למה אתה לא רוצה שתהיה גישה?
&nbsp
צרף קוד דוגמה.
 

YIM222

New member
לדוגמא:(בהנחה שיש object classA)

private class ClassB{
private ClassA a = new ClassA();
private ClassA[] array;
private int[] array2;

public getA(){return a;} //and so on do getter to all fields above....
public static void main..... {
new get...();
}
}



לדוגמא במחלקה הזו. מה משתמש יוכל לשנות ע"י שימוש בget? . רק אולי על המשתנה a אני קצת מבין שיהיה לו גישה ישירה לאיברים הזמינים של האובייקט , אבל היי זה גם ככה מן הסתם אובייקט שמיש ומחלקות אחרות גם משתמשות בו. אבל על שאר השדות בכלל אני לא מבין מה אפשר לעשות רק עם get.
 

BravoMan

Active member
לא כתבת מה ClassA עושה...

אם ל-ClassA יש פונקציות set, או שדות שהם public, כל מי שמשתמש ב-getA על ClassB, יוכל לשנות את התוכן של איבר a, בלי ש-B ידע על כך.
היות ובדוגמה שלך B הוא זה שאחראי לייצר את התוכן של a בצורה פנימית (new) הרי ששינוי מבחוץ הוא מצב רע ולא צפוי.
&nbsp
בנוסף, אם יש get שמחזיר את array, כל אחד בחוץ יוכל לשנות את האיברים של array, כולל להפוך אותם ל-null, ושוב, בלי ש-ClassB יהיה מודע לזה.
אותו כנ"ל לגבי array2 אפשר יהיה לשנות את המספרים השמורים בו.
&nbsp
מה כל זה אומר?
שבכל פעם שקוד כלשהו במחלקה B ניגש לאחד האיברים שלה, אין לו מושג מה יש שם, ומה המצב.
אין לו דרך לוודא שאין שם ערכים לא חוקיים מבחינת B.
למשל, אולי ב-array2 אסור שיהיו מספרים גדולים מ-1000? או מספרים שליליים?
בגלל שכל אחד יכול לדחוף ל-array2 כל מספר שהוא רוצה מבחוץ, אין דרך לאכוף את המגבלה הזו.
&nbsp
אלא אם כן תדאג שכל פעם שעושים get, יוחזר עותק של המערך (clone) במקום המקור, והערכים יוכנסו למערך אך ורק דרך מתודות של B.
 

selalerer

New member
ב-3 אתה מאפשר למישהו מחוץ לאובייקט לשנות מבנה נתונים פנימי.

זאת נכות שקיימת ב-Java וגם ב-#C (לפחות בעבר, אולי הם הוסיפו פיצ'ר מאז).
&nbsp
ב-++C אתה יכול להחזיר const pointer או const reference וזה גם חוסך לך את ההעתקה וגם מאפשר לחשוף את הנתונים החוצה בצורה בטוחה.
&nbsp
לכאורה התחליף של השפות האלו זה interface שלא מאפשר לעשות פעולות של שינוי על המידע אבל להוסיף interface עבור כל אובייקט שאתה רוצה להחזיק מ-getter זה overhead רציני.
 
למעלה