
Shape כמחלקת בסיס, ו-Circle ו-Rectangle שיורשות ממנה.Shape יכולה לקבל כל אובייקט שיורש ממנו, כולל Shape עצמו. בדוגמה פונקציית display מקבלת עיגול ומלבן.Shape יכול להחזיק עיגולים, מלבנים וכל צורה אחרת שיורשת ממנו, והעבודה נעשית על מערך אחד במקום כמה מערכים.Shape יכול בהמשך התוכנית להצביע על צורה שייקבעה על ידי המשתמש, עיגול או מלבן, ולשמור על אותו שם.Person שאינה יורשת את Shape לא ניתנת להשמה לרפרנס מסוג Shape, והקומפיילר יציג שגיאה.Circle מקבל רק עיגולים או צורות שנגזרות מעיגול, ולכן מלבן לא ייכנס אליו.הטקסט המלא של הדקות הראשונות בהרצאה «יתרונות של Reference Type» בקורס הווידאו של PracticU – כתוביות בעברית עם זמן התחלה לכל פסקה. כך תוכלו לקרוא ולחפש את הנושאים לפני שמתחילים ללמוד.
אחרי שראינו מה זה value type ומה זה reference type ומה נוצר בזיכרון מהם, ואחרי שראינו איך הזיכרון נראה עבור מערכים של value type ועבור מערכים של reference type, אנחנו הולכים עכשיו לראות מה היתרון בעצם ב-reference type.
למה לפעמים זה טוב לנו שהתמונת זיכרון נראית כ-reference type, למרות שככה זה תמיד עובד בקלאסים, אבל האם יש שם איזשהו יתרון מסוים, ואם כן, איך אנחנו יכולים להשתמש איתו לטובתנו?
לצורך כך אנחנו הולכים לבנות כמה מחלקות שקשורות ביניהם בקשר של הורשה. אז בוא נניח שהתוכנית שלנו מתעסקת עם כל מיני צורות תוכנית גרפית.
יש לנו, בוא נניח, עיגולים ויש לנו מלבנים בתוכנית. ולכל העיגולים יש מיקום על המסך שנבנה על ידי x ו-y וגם לכל המלבנים יש איזשהו מיקום על המסך אבל אנחנו רואים שיש ביניהם כל מיני דברים משותפים ולכן כדאי שנבנה איזושהי מחלקת בסיס עבור כל הצורות
אז מן הסתם נקרא לה שייפ והיא תתאר לנו צורה אחת בודדת. בואו נצרף את המחלקה, יש לנו שייפ, בתוך שייפ נגדיר x, y, נגדיר איזשהו קונסטרקטור ונגדיר איזושהי פונקציית הצגת פרטים.
נציג את הפרטים, אז יש לנו את המחלקה שייפ, בואו נוסיף מחלקה עבור עיגול, נקרא לה סרקל, נגדיר שהיא תירש את שייפ, זה אומר שאוטומטית קיבלנו את כל מה שהיה ל-shape כמו x ו-y.
נגדיר איזשהו רדיוס, קונסטרקטור, קורא לקונסטרקטור מחלקת הבסיס, שולח לה x ו-y ומעדכן את ה-data member radius.
במציאות כמובן שהוא אמור להיות עם פרופרטי, אבל כרגע עשינו את זה בלי פרופרטי. יש לנו פה פרינט, קוראת ל-base print, ומדפיסה גם את הרדיוס. צורך ב-right line, ב-shape רק right.
יופי. אז יש לנו את הסרקל ונשאר לנו לבנות רק את המחלקה שמתארת מלבן. בואו נוסיף אותה. יורשת, שייפ, מכילה, רוחב, גובה.
מלבן בעולם פיתוח התוכנה מחזיק רוחב וגובה ולא אורך ורוחב, מפני שבגיאומטריה אורך ורוחב הם יכולים להיות בשני ממדים, כלומר בשני כיוונים. כי אורך זה הצלע הארוכה, אז היא יכולה להיות שוכבת והיא יכולה להיות עומדת, תלוי איך מציירים את המלבן.
כאשר אנחנו מגדירים מלבן אנחנו רוצים תמיד שהרוחב יהיה מה ששוכב אז אנחנו קוראים לזה רוחב ומה שעומד יהיה גובה אז יש לנו width וheight קונסטרקטור מקבל int x, int y, double width, double height שולחים למחלקת הבסיס את ה-x ואת ה-y ומגדירים width וheight
גם כאן כמובן היה יותר הגיוני ליצור פרופרטיז ואנחנו כבר מכירים מה זה פרופרטי אז נחסוך מאיתנו את ההדגמה הזאת. אז יש לנו פה פרינט, אנחנו רוצים לקרוא לבייס פרינט ואנחנו רוצים להדפיס בנוסף גם את הוויד וגם את ההייט.
אוקיי, דיר כאן שווה כמו שעשינו במקרים הקודמים כאן ויש לנו את הכל בשייפ מוכן. אז יש לנו עכשיו מספר המחלקות עבור תיאור צורות.
יש לנו שייפ שהיא מחלקת הבסיס, יש לנו מחלקה שמתארת עיגול, יורשת את שייפ ומוסיפה רדיוס, לאיגוד יש רדיוס ויש לנו מחלקה שמתארת מלבן והיא גם כן צורה והיא רואה שאתה צ'ייפ ומוסיפה רוחב וגובה כי למלבן יש רוחב וגובה בנוסף ל-X ו-Y.
כעת אנחנו רוצים לעבוד עם המחלקות האלה. אז אנחנו הולכים לפרוגרם שלנו ואנחנו רוצים לעבוד איתם ואני הולך עכשיו ליצור כמה דברים עם המחלקות האלה ותוך כדי זה להראות מה היתרונות ברפרנס טייפ.
אז דבר ראשון בוא נניח שאנחנו רוצים שתהיה לנו איזושהי פונקציה פה. סטטי או לא סטטי לא משנה אבל הפונקציה הזאת בוא נניח היא מציגה איזשהו דוח לגבי צורה שהיא מקבלת ואנחנו רוצים שהפונקציה הזאת תקבל כל צורה שיכולה להיות נקרא לה נניח דיספליי והיא תציג את הצורה אז מה אנחנו בדיוק מקבלים הרי צורה יכולה להיות סרקל וצורה יכולה
להיות ריקטנגל ואולי בהמשך צורה יכולה להיות טריאנגל זה משולש וצורה יכולה להיות Square שזה ריבוע וכל מיני צורות אחרות.
אז אנחנו צריכים להבין איזשהו חוק מסוים שקיים בנוגע ל-Reference Type. החוק הזה הוא חוק מאוד מאוד בסיסי באובג'קט אוריינטד והוא בעצם בסיס לתחום הפולימורפיזם שאנחנו נראה בהמשך.
והחוק אומר דבר כזה אם קיים לכם איזשהו הוא רפרנס, הוא יכול לקבל כתובת של אובייקט שנגזר ממחלקת הרפרנס. בואו נשים שנייה את זה בצד ונבין על מה אנחנו בעצם מדברים פה.
אם אנחנו יוצרים אובייקט סרקל, אנחנו יודעים שאנחנו כותבים circle c שווה new circle. אני כבר רואה שאין לי פה קונסטרקטור ריק, אז בואו נוסיף לו איזשהו קונסטרקטור ריק, גם לו, גם ל-shape וגם ל-rectangle, למרות שאני לא הייתי חייב את זה, אבל בשביל שיהיה לנו אפשרות אולי ליצור אובייקטים ריקים,
יש לנו קונסטרקטורים. כעת יש לנו פה אובייקט סרקל. אם אנחנו רוצים ליצור אובייקט ריקטנגל, אנחנו פשוט היינו רושמים ריקטנגל r שווה ניו ריקטנגל.
אם היינו רוצים ליצור אובייקט שייפ, היינו פשוט רושמים שייפ s שווה ניו שייפ. לא יודע אם זה היה כל כך הגיוני ליצור אובייקט שייפ, כי המטרה של המחלקה זה רק להיות מחלקת בסיס, לצורך הדוגמה בואו נניח שאנחנו יכולים לעשות את זה.
אז אנחנו ראינו בעולם ה-reference type מה זה בדיוק ה-C או ה-R או ה-F שיש לנו פה. ואנחנו ראינו שזה לא בייקט אמיתי אלא רפרנס. זה אומר שהכלנו לעשות דבר כזה ודבר כזה ודבר כזה.
זאת אומרת כאן ראינו שאנחנו יכולים ליצור רפרנס ואז להכניס לתוך הרפרנס אובייקט שייפ. פה יצרנו רפרנס מסוג סרקל והכנסנו בתוכו בייקט סרקל.
ופה יצרנו רפרנס מסוג ריקטנגל ואז החזרנו בתוכו אובייקט ריקטנגל. וכמובן שאם אנחנו רוצים ליצור את האובייקטים האלה אז מה שעשינו פה זה ממש בסדר. אבל החוק הזה שדיברנו עליו אומר את הדבר הבא הרפרנס יכול להיות מסוג שייפ כאשר בתוכו אנחנו מכניסים אובייקט שייפ או אם הוא מטיפוס שייפ אנחנו יכולים להכניס בתוכו גם אובייקט שנגזר משייפ זאת אומרת במילים אחרות במקום
לרשום פה סרקל אנחנו יכולים לרשום שייפ אבל רגע מה זה נותן לי? אז קודם כל זה אפשרי לביצוע. אם אנחנו עכשיו ניגש לפרויקט שלנו ונבצע בנייה של הפרויקט אנחנו יכולים לראות פה למטה שהוא כותב לנו rebuild all succeeded.
זאת אומרת שמבחינת שפת התכנות אין פה שום שגיאה וזה חוקי לגמרי. זאת אומרת אנחנו יכולים ליצור רפרנס מטיפוס של מחלקת בסיס זה להכניס לתוך ה-reference הזה אובייקט או ממחלקת הבסיס, אותו המחלקה שיצרה את ה-reference, או ממחלקה נגזרת.
אנחנו לא נוכל להכניס אליו אובייקט אחר. לדוגמה, אם היה לי פה קלאס person שבקלאס person היה לי public string full name, לא היינו יכולים עכשיו להגדיר שייפ ניחf2 שווה new person.
הדבר הזה לא היה עובר וכבר אנחנו רואים שיש לנו פה שגיאה. מפני שפרסון לא יורש את שייפ, הוא לא אמור לרשת את שייפ והוא לא יורש את שייפ.
אנחנו יכולים להכניס לרפרנס שייפ רק אובייקט שייפ כמו במקרה הזה או כל אובייקט שנגזר משייפ. קודם כל החוק הזה קיים, זה אנחנו יכולים למחוק והוא חוקי לגמרי ואנחנו עכשיו הולכים לראות מה היתרון בחוק הזה.
פה אנחנו יכולים לחזור בחזרה לפונקציה שאנחנו בנינו והפונקציה הזאת אומרת תביאו לי כל צורה שאתם רוצים, אני אציג פשוט את הצורה או את הפרטים שלה אז אם אני רוצה להעביר כל אובייקט מכל צורה שהיא לפונקציה אני יכול לקבל רפרנס שייפ בוא נניח שמה שאני עושה פה זה פרינט ומציג
את הפרטים של הצורה שקיבלתי נקרא לפונקציה הזאתי נניח פרינט שייפ עכשיו השאלה היא מה אנחנו יכולים לשלוח לפונקציה אז בואו נראה נחזיר את זה לפורמט הקודם שהיה לנו נניח שיש לנו פה שלושה אובייקטים יש לנו שייפ יש לנו סרקל ויש לנו ריקטנגל אנחנו יכולים עכשיו לקרוא לפונקציה print shape ולשלוח את השייפ את הסרקל ואת הריקטנגל
בואו נבצע בנייה ונראה שהוא כותב לנו rebuild all succeeded ברור שהצלחנו לשלוח אותם הרי הרפרנס הוא שייפ אבל רגע מה היה קורה אם הרפרנס היה מהטיפוס האמיתי זאת אומרת יש לנו פה רפרנס שנקרא c והוא מסוג סרקל והוא מצביע על אובייקט סרקל יש לנו פה רפרנס שהסוג שלו
זה ריקטנגל והוא מצביע על אובייקט ריקטנגל ואנחנו שלחנו עכשיו את הרפרנסים האלה אבל מה זה משנה שלחנו כתובת כתובת יכולה להצביע על אובייקט סרקל או על אובייקט ריקטנגל ושימו לב שכאשר אנחנו מבצעים ריבילד הוא כותב לנו פה ריבילד all succeeded אז כאן אנחנו רואים יתרון ראשון היתרון הזה
נקרא פונקציה הטרוגנית זה אומר שהיא יכולה לקבל כל מיני טיפוסים שונים. איך זה יכול להיות? הפונקציה קיבלה טיפוס בסיס, שייפ.
זה אומר שעכשיו בגלל החוק הזה שראינו, אובייקט, או יותר נכון רפרנס שייפ, מסוגל להצביע על כל אובייקט שהוא גם מטיפוס שייפ וגם אובייקטים שיורשים את שייפ.
לכן אין שום בעיה לשלוח לפונקציה אובייקט שייפ או אובייקט סרקל כי הוא יורש את שייפ או אובייקט ריקטנגל כי הוא יורש את שייפ.
זה בעצם היתרון הראשון שקיים בחוק הזה, והוא נולד עקב מבנה הזיכרון של ה-reference type. אז יתרון ראשון, ניתן לכתוב פונקציה הטרוגנית, היא מקבלת רפרנס מטיפוס הבסיס, ולכן אנחנו יכולים לשלוח לפונקציה כל אובייקט שהוא.
הפונקציה הזאת עכשיו יכולה לעבוד על הרבה אובייקטים ועל הרבה צורות. יתרון שני, בוא נניח שקיימים לנו המון עיגולים והמון מלבנים בתוכנית, אנחנו רוצים את כל העיגולים ואת כל המלבנים ואת כל שאר הצורות שיכולות להיות לנו משולשים
וקווים ומתומנים וכולי שכולם יורשים את צ'ייפ. אנחנו רוצים לנהל את כולם במערך אחד. אנחנו לא רוצים לנהל את כל הצורות בהרבה מערכים.
כי אנחנו רוצים לרוץ על מערך אחד ויחיד ולהציג את כל הצורות, או לרוץ על מערך אחד ויחיד ולשמור את כל הצורות שיש בו.
אז השאלה היא מה סוג המערך שיכול להיות. אם אנחנו נבנה מערך מ-Circle בוא נניח לגודל 100, כל תא במערך הזה הסוג שלו הוא סרקל וכמובן שבגלל שסרקל זה קלאס תא עצמו הוא רפרנס ראינו