פרק לדוגמה - מבט לחלונות

‫פרק‬
‫‪1‬‬
‫מהו טיפוס מורכב?‬
‫עד כה השתמשנו במושג טיפוס בשני הקשרים‪ :‬לפני שנחשפנו למושגים של תכנות מונחה עצמים‬
‫‪ ,)int‬משתנה‬
‫דיברנו על טיפוס בהקשר של סוג הערך של משתנים‪ .‬למשל‪ :‬משתנה מטיפוס שלם (‬
‫מטיפוס ממשי ( ‪ ,)double‬משתנה מטיפוס בוליאני ( ‪ .)boolean‬במסגרת תכנות מונחה עצמים דיברנו‬
‫על הגדרת טיפוס על ידי המשתמש‪ ,‬למשל‪ :‬הטיפוסים תלמיד ( ‪ )Student‬או שיר (‪:)Song‬‬
‫‪ ‬בספר יסודות מדעי המחשב – חלק ב'‪ :‬במחלקה ‪ TestStudent‬בעמוד ‪ ,140‬הוגדר משתנה בשם‬
‫‪ stu1‬מטיפוס ‪ – Student‬שערכו הוא עצם מן הטיפוס;‬
‫‪ ‬בספר יסודות מדעי המחשב – חלק ב'‪ :‬דוגמה פתורה ‪ 1‬בעמוד ‪ 153‬במחלקה ‪SongProgram1‬‬
‫הוגדר משתנה בשם ‪ songs‬שהוא מערך של עצמים מטיפוס ‪ – Song‬ערך של כל אחד מתאי‬
‫המערך הוא עצם מן הטיפוס‪.‬‬
‫טיפוס הוא טיפוס בכל מקרה‪ ,‬גם אם הוא מוגדר בתוך שפת התכנות‪ ,‬וגם אם הוא מוגדר על ידי‬
‫המשתמש‪ .‬כפי שמשתנה יכול להיות מוגדר על פי טיפוס שהוגדר על ידי המשתמש‪ ,‬כך גם תכונה‪.‬‬
‫– טיפוס‬
‫תכונה של טיפוס חדש יכולה להיות מטיפוס אחר שהוגדר קודם על ידי המשתמש‪ .‬כלומר‬
‫המשתמש בטיפוס‪ .‬לטיפוס כזה נקרא טיפוס מורכב‪.‬‬
‫טיפוס מורכב ‪ -‬לשם מה?‬
‫העיקרון עליו מושתת תכנות מונחה עצמים הוא חלוקת בעיה לטיפוסים הנדרשים לפתרונה וכן‬
‫שימוש בטיפוסים שכבר הוגדרו (בשפה או ע"י המשתמש) לצורך הגדרת טיפוסים חדשים‪ .‬פתרון בעיה‬
‫בגישה מונחית עצמים מתחיל בזיהוי העצמים הנדרשים לפתרונה‪ ,‬ובהתאם לכך הגדרה כללית של‬
‫הטיפוסים שלהם‪ .‬העצמים נבנים בהתאם לטיפוסים‪ .‬דוגמה אחת לשילוב של טיפוסים היא למשל‬
‫‪ .)7‬באופן‬
‫מערך של עצמים מטיפוס שהוגדר על ידי המשתמש (יסודות מדעי המחשב‪ ,‬חלק ב‪ ,‬פרק‬
‫דומה ניתן לעשות שימוש בכל טיפוס שהגדיר המשתמש לצורך הגדרת טיפוסים חדשים‪.‬‬
‫טיפוס מורכב הוא טיפוס המוגדר על ידי המשתמש שחלק מן התכונות שלו הן מטיפוס‬
‫שאינו בסיסי בשפה אשר הוגדר על ידי המשתמש או שהוא כלול בספריות של השפה‪.‬‬
‫הגדרה‬
‫למשל‪ :‬אם הוגדר הטיפוס גלגל ניתן להגדיר טיפוס מכונית שאחת התכונות שלו היא שיש בו‬
‫גלגל‪ .‬התכונה גלגל היא מן הטיפוס גלגל‪ .‬כלומר הטיפוס מכונית משתמש בטיפוס גלגל‪.‬‬
‫‪...................................................................................................................................‬‬
‫‪.....................................................................................................................................................‬‬
‫‪.....................................................................................................................................................‬‬
‫עיצוב תוכנה – טיפוס מורכב‬
‫©‬
‫כל הזכויות שמורות ל'מבט לחלונות'‬
‫‪7‬‬
‫הגדרה‬
‫מושגים חדשים בפרק‬
‫‪ ‬טיפוס בסיסי – טיפוס המוגדר כבנוי בשפה (מספר שלם‪ ,‬מספר ממשי‪ ,‬תו‪ ,‬ערך בוליאני)‪.‬‬
‫‪ ‬טיפוס פשוט (‪ – )Simple class‬טיפוס המוגדר על ידי המשתמש שהתכונות שלו הן‬
‫מטיפוסים בסיסיים‪.‬‬
‫‪ ‬טיפוס מורכב (‪ – )Composed class‬טיפוס המוגדר על ידי המשתמש (או מוגדר בשפה)‬
‫שחלק מן התכונות שלו הן מטיפוס שאינו בסיסי בשפה‪.‬‬
‫‪ ‬טיפוס משתמש בטיפוס – טיפוס שבתוך ההגדרה שלו יש שימוש בטיפוס אחר שהוגדר על ידי‬
‫המשתמש‪ .‬השימוש יכול להיות בתכונה ‪ /‬בפרמטר ‪ /‬במשתנה ‪ /‬בערך מוחזר‪.‬‬
‫‪ ‬מודולאריות ( ‪ – )Modularization‬חלוקה של בעיה למספר טיפוסים המשתמשים זה בזה‪,‬‬
‫ויכולים לשמש גם לצורך פתרון בעיות אחרות‪.‬‬
‫‪ ‬הכמסה ( ‪ – )Encapsulation‬עצם על כל תכונותיו מומשל לכמוסה ומהווה יחידה אחת‪.‬‬
‫כיחידה אחת העצם משמש כערך (אחד) של תכונה ‪ /‬משתנה ‪ /‬פרמטר ‪ /‬ערך מוחזר‪.‬‬
‫דוגמה ‪ :1‬קלמר‬
‫העצם עפרון ניתן כדוגמה לעצם‪ ,‬עכשיו אנחנו כבר יודעים שלפני שאנו מתייחסים אל העצם עפרון יש‬
‫להגדיר את הטיפוס עפרון‪ .‬באותו אופן אנו יכולים להגדיר את הטיפוסים‪ :‬מחדד‪ ,‬מחק ומספריים ‪.‬‬
‫לכל אחד מן הטיפוסים האלה יש תכונות המאפיינות אותו ופעולות שניתן להפעיל על עצמים שנבנו על‬
‫פיו‪ .‬נבחר עצמים מכל טיפוס ונרצה להרכיב קלמר‪ .‬ל קלמר יש בעלים ויש מחיר ויהיו בו ‪ 2‬עפרונות‪,‬‬
‫מחדד‪ ,‬מחק‪ ,‬ומספריים‪ ,‬כלומר – אלו התכונות שלו‪ .‬קלמר מסוים יהיה של אדם מסוים ויהיה לו‬
‫מחיר מסוים והוא יכיל – שני עפרונות מסוימים (עצמים מטיפוס עפרון)‪ ,‬מחדד מסוים (עצם מטיפוס‬
‫מחדד)‪ ,‬מחק מסוים (עצם מטיפוס מחק)‪ ,‬ומספריים מסוימים (עצם מטיפוס מספריים)‪ .‬הקלמר הזה‬
‫הוא עצם‪ .‬יש הרבה קלמרים שזו תכולתם‪ ,‬לכן ניתן להגדיר את הטיפוס קלמר‪ .‬בטיפוס קלמר יוגדרו‬
‫‪ 7‬תכונות‪ ,‬וכל תכונה היא מהטיפוס המתאים לה‪ .‬הטיפוס קלמר יקרא טיפוס מורכב כי הוא משתמש‬
‫בטיפוסים אחרים שהוגדרו על ידי המשתמש‪ :‬עפרון‪ ,‬מחדד‪ ,‬מ חק‪ ,‬מספריים‪ .‬נקרא לעצם מן הטיפוס‬
‫קלמר עצם מורכב‪ ,‬מאחר וערכי התכונות שלו הם עצמים ולא טיפוסים בסיסיים‪.‬‬
‫דוגמה ‪ :2‬שיחת טלפון‬
‫ניתן לאפיין את התכונות הבאות עבור שיחת טלפון ‪ :‬קו‪-‬טלפון מתקשר‪ ,‬קו‪-‬טלפון מקבל‪ ,‬האדם‬
‫המתקשר‪ ,‬האדם המקבל‪ ,‬זמן התחלת השיחה וזמן סוף השיחה‪ .‬מאפיינים אלו משותפים לכל שיחות‬
‫הטלפון ולכן מתאים להגדיר את הטיפוס שיחת‪-‬טלפון‪ .‬מהו קו‪-‬טלפון? קו‪-‬טלפון אף הוא טיפוס‬
‫שהתכונות שלו למשל הן‪ :‬מספר הקו והבעלים של הקו‪ .‬הערך של התכונה קו‪-‬טלפון מתקשר הוא‬
‫קו‪-‬טלפון ‪.‬‬
‫עצם מטיפוס קו‪-‬טלפון‪ .‬כך גם הערך של התכונה קו‪-‬טלפון מקבל הוא עצם מטיפוס‬
‫‪8‬‬
‫עיצוב תוכנה – טיפוס מורכב‬
‫©‬
‫כל הזכויות שמורות ל'מבט לחלונות'‬
‫הטיפוס שיחת‪-‬טלפון הוא טיפוס מורכב כי יש לו תכונות מטיפוס פשוט שהערכים שלהם הם עצמים‪.‬‬
‫ערך של משתנה‪/‬תכונה מטיפוס שיחת‪-‬טלפון הוא עצם מורכב‪ ,‬כי יש לו תכונות מטיפוס פשוט‬
‫שהערכים שלהם הם עצמים‪.‬‬
‫דוגמה ‪ :3‬כיתה ובית ספר‬
‫עסקנו רבות בטיפוס תלמיד‪ .‬הגדרנו גם מערך של תלמידים‪ .‬ניתן להשתמש במערך של תלמידים‬
‫כתכונה של הטיפוס כיתה‪ .‬לטיפוס כיתה יש את המאפיינים‪ :‬שכבה‪ ,‬מספר כיתה‪ ,‬מחנך הכיתה‪,‬‬
‫מערך תלמידי הכיתה‪ .‬עצם מן הטיפוס כיתה יהיה כיתה מסוימת‪ ,‬למשל כיתה בשכבה י'‪ ,‬שמספרה ‪,7‬‬
‫המחנך שלה הוא שמואל שלומיאלי‪ ,‬ויש בה תלמידים שכל אחד מהם הוא עצם במערך התלמידים‪.‬‬
‫הטיפוס כיתה משתמש בטיפוס תלמיד‪ .‬גם עבור המורה ניתן להגדיר טיפוס נפרד‪ .‬במקרה זה הטיפוס‬
‫כיתה היה משתמש בטיפוס תלמיד וגם בטיפוס מורה‪ .‬ניתן להתייחס גם לטיפוס נוסף‪ ,‬הטיפוס בית‪-‬‬
‫ספר‪ .‬המאפיינים של בית ספר הם למשל‪ :‬שם‪ ,‬עיר‪ ,‬כתובת‪ ,‬מערך מורי בית הספר‪ ,‬ומערך כיתות‬
‫ביה"ס‪ .‬כלומר יש לנו טיפוס מורכב המשתמש בטיפוס מורה וגם בטיפוס כיתה‪ ,‬כאשר הטיפוס כיתה‬
‫משתמש בטיפוס מורה וגם בטיפוס תלמיד‪ .‬האפשרות של פיתוח מודולארי ‪ -‬זו המשמעות‪ ,‬החשיבות‬
‫והיתרון של תכנות מונחה עצמים‪ .‬בניית טיפוסים יכולה להתבצע באופן בלתי תלוי‪ .‬בהתאם לצרכי‬
‫פתרון הבעיה ישולבו טיפוסים בפרויקט‪ ,‬כך שטיפוס יכול תמיד להשתמש בטיפוסים שהוגדרו קודם‪.‬‬
‫לסיכום‪ ,‬בשלוש הדוגמאות שהוצגו לעיל הדגש היה על התכונות של הטיפוסים שהערך שלהם הוא‬
‫עצם‪ .‬הכללים של הפעלת פעולות על עצמים נשמרים גם כאשר העצמים מהווים ערכים של תכונות‬
‫בעצם אחר ‪ -‬מורכב‪ .‬בכל מקרה על כל עצם ניתן להפעיל את אוסף הפעולות המוגדרות בטיפוס שלו‪.‬‬
‫בטיפוס המורכב‪ ,‬כמו בכל טיפוס‪ ,‬מוגדרות תכונות ופעולות‪ .‬הפעולות שיוגדרו בטיפוס מורכב הן‬
‫פעולות שיופעלו על עצם מן הטיפוס הזה‪.‬‬
‫לסיכום‪ ,‬לעקרון המבנה של חלוקה מודולארית לטיפוסים יש חשיבות ומשמעות רבה ‪ .‬בעבודה עם‬
‫טיפוס אחד בלבד אי אפשר להוציא אל הפועל באופן משמעותי את העקרונות של תכנות מונחה‬
‫עצמים‪ .‬העקרונות של תמ"ע והיתרונות שלהם באים לידי ביטוי כאשר יש שילוב ושימוש במספר‬
‫טיפוסים כמו למשל בדוגמה של השילוב בין הטיפוסים‪ :‬תלמיד‪ ,‬מורה‪ ,‬כיתה‪ ,‬ביה"ס‪.‬‬
‫שפת ‪UML‬‬
‫שפת ‪ (Unified Modeling Language) UML‬היא שפה הכוללת אוסף של סימונים מוסכמים לתיאור‬
‫מערכת תוכנה מהיבטים שונים‪ .‬קיום של שפת תיאור אחידה מהותי כדי שמפתחים שונים וקוראים‬
‫שונים של תוכנה יוכלו להתמצא בה ולמעשה "לדבר באותה שפה"‪ .‬השפה כוללת כללים לתיאורים‬
‫גראפיים שונים של מערכת תוכנה מנקודות מבט שונות וקיימת הסכמה רחבה בתעשייה להשתמש‬
‫בה כסטנדרט‪ .‬בספר זה נשתמש בשני מרכיבי תיאור מתוך ה‪ )1( :UML -‬תיאור מחלקה ‪ -‬הכולל‪ :‬שם‪,‬‬
‫תכונות ופעולות; ( ‪ )2‬תרשים מחלקות – תרשים המתאר את הקשר בין מחלקות שונות בפרויקט‪.‬‬
‫קיימים סוגים שונים של קשרים בין מחלקות‪ .‬ביחידת לימוד זו הקשר היחיד בו נשתמש הוא קשר‬
‫של שימוש‪/‬הכלה – הבא לידי ביטוי כאשר במחלקה אחת יש תכונות מטיפוס של מחלקה אחרת‪.‬‬
‫עיצוב תוכנה – טיפוס מורכב‬
‫©‬
‫כל הזכויות שמורות ל'מבט לחלונות'‬
‫‪9‬‬
‫ייצוג של טיפוס מורכב בתרשים‬
‫טיפוס מורכב מיוצג בהתאם לכללי הייצוג עבור כל טיפוס‪ .‬בתרשימים הבאים נפרט עבור כל תכונה‬
‫גם את הטיפוס שלה‪ .‬נציג את הטיפוסים המתוארים בדוגמה ‪ 3‬על ידי תרשים ‪ .UML‬בתרשים ‪UML‬‬
‫המתאר מחלקה בדרך כלל לא מופיעה העמודה הימנית – כי מוסכם שאלו החלקים הקיימים בתיאור‬
‫של כל מחלקה‪ .‬תרשימי ‪ UML‬כתובים בשפת התכנות ולא בשפה טבעית‪ .‬בדוגמה זו יוצג תרשים‬
‫בעברית‪ .‬בדוגמאות הבאות נעבור לייצוג פורמאלי בשפת ‪.UML‬‬
‫‪ :‬הטיפוס בנקודת המעוין משתמש בטיפוס שהקו מתחיל ממנו‪.‬‬
‫משמעות הקו‬
‫מיקום היציאה ו‪/‬או הכניסה של הקו אינו בעל משמעות‪.‬‬
‫הטיפוס‬
‫תלמיד‬
‫הטיפוס‬
‫מורה‬
‫תכונות‬
‫שם מטיפוס מחרוזת‬
‫ת‪.‬ז‪ .‬מטיפוס מחרוזת‬
‫ציון במתמטיקה מטיפוס שלם‬
‫מטיפוס שלם‬
‫ציון באנגלית‬
‫מטיפוס שלם‬
‫ציון בלשון‬
‫תכונות‬
‫שם מטיפוס מחרוזת‬
‫ת‪.‬ז‪ .‬מטיפוס מחרוזת‬
‫ותק בהוראה מטיפוס שלם‬
‫בעל תעודת הוראה מטיפוס בוליאני‬
‫מקצועות הוראה מטיפוס מערך מחרוזות‬
‫פעולות‬
‫העלה‪-‬ציון(_מקצוע‪_ ,‬נקודות)‬
‫החזר‪-‬ממוצע( )‬
‫הדפס‪-‬תעודה( )‬
‫פעולות‬
‫הגדל‪-‬ותק‪-‬בשנה( )‬
‫הוסף‪-‬מקצוע‪-‬הוראה(_מקצוע)‬
‫האם‪-‬מלמד‪-‬מקצוע(_מקצוע)‬
‫‪2‬‬
‫‪5‬‬
‫הטיפוס‬
‫כיתה‬
‫תכונות‬
‫מטיפוס תו‬
‫שכבה‬
‫מטיפוס שלם‬
‫מספר‬
‫מטיפוס מורה‬
‫מחנך‬
‫מספר תלמידים מטיפוס שלם‬
‫מטיפוס מערך של תלמידים‬
‫תלמידים‬
‫פעולות‬
‫הוסף‪-‬תלמיד(_תלמיד)‬
‫קבע‪-‬מחנך(_מורה)‬
‫האם‪-‬תלמיד‪-‬לומד‪-‬בכיתה(_תלמיד)‬
‫החזר‪-‬תלמיד‪-‬מצטיין( )‬
‫הטיפוס‬
‫‪4‬‬
‫‪1‬‬
‫בית ספר‬
‫תכונות‬
‫שם‬
‫עיר‬
‫מורים‬
‫כיתות‬
‫פעולות‬
‫הוסף‪-‬תלמיד‪-‬לכיתה(_שכבה‪_ ,‬מספר‪_ ,‬תלמיד)‬
‫הוסף‪-‬מורה(_מורה)‬
‫באיזו‪-‬כיתה‪-‬תלמיד‪-‬לומד(_תלמיד)‬
‫החזר‪-‬תלמיד‪-‬מצטיין( )‬
‫מטיפוס מחרוזת‬
‫מטיפוס מחרוזת‬
‫מטיפוס מערך של מורים‬
‫מטיפוס מערך של כיתות‬
‫הערה‪ :‬התרשים כולל הגדרת תכונות מלאה והגדרת פעולות חלקית‪ .‬אין למשל פעולות בונות‪.‬‬
‫‪10‬‬
‫עיצוב תוכנה – טיפוס מורכב‬
‫©‬
‫‪3‬‬
‫כל הזכויות שמורות ל'מבט לחלונות'‬
‫הסבר החיצים בתרשים‪:‬‬
‫קו ‪ – 1‬בטיפוס כיתה יש תכונה המשתמשת בטיפוס מורה‪ :‬התכונה מחנך מטיפוס מורה‪.‬‬
‫קו ‪ – 2‬בטיפוס כיתה יש תכונה המשתמשת בטיפוס תלמיד‪ :‬התכונה תלמידים מטיפוס מערך של‬
‫תלמיד‪.‬‬
‫קו ‪ – 3‬בטיפוס בית ספר יש תכונה המשתמשת בטיפוס מורה‪ :‬התכונה מורים מטיפוס מערך של מורה‪.‬‬
‫קו ‪ – 4‬בטיפוס בית ספר יש תכונה המשתמשת בטיפוס כיתה‪ :‬התכונה כיתות מטיפוס מערך של כיתה‪.‬‬
‫קו ‪ –5‬בטיפוס בית ספר יש פעולה המשתמשת בפרמטר מטיפוס תלמיד‪ :‬הפעולה‬
‫לכיתה(_שכבה‪_ ,‬מספר‪_ ,‬תלמיד)‪.‬‬
‫הוסף‪-‬תלמיד‪-‬‬
‫תרשים מסוג זה מתאר את הקשרים שיש בין טיפוסים ומקל מאד על תהליך תכנון הטיפוסים הכולל‬
‫את זיהוי התכונות והפעולות שלהם‪ ,‬ומקל גם על פיתוח הפעולות תוך שימוש בפעולות המוגדרות‬
‫בטיפוסים האחרים‪.‬‬
‫שים ‪ :‬הפעולה החזר‪-‬תלמיד‪-‬מצטיין( ) מוגדרת בשני טיפוסים‪ .‬הפעולה המוגדרת בטיפוס כיתה‬
‫תופעל על עצם מטיפוס כיתה ותחזיר את התלמיד המצטיין בכיתה‪ .‬הפעולה המוגדרת בטיפוס ביה"ס‬
‫תופעל על עצם מטיפוס ביה"ס ותחזיר את התלמיד המצטיין בביה"ס‪ .‬גם בשפת התכנות ניתן להגדיר‬
‫פעולות בעלות שם זהה בטיפוסים שונים‪ .‬מאחר ובזמן הפעלת הפעולה היא תופעל על עצם מסוים‪,‬‬
‫ועצם יכול להיות רק מטיפוס אחד‪ ,‬אין בעיה בזיהוי הפעולה שיש לבצע‪ .‬הפעולה שתתבצע היא זו‬
‫המוגדרת בטיפוס של העצם עליה היא מופעלת‪.‬‬
‫כללי הפיתוח של טיפוס מורכב הם בדיוק כמו כללי הפיתוח של כל טיפוס‪ .‬נדגים בשלבים את פיתוח‬
‫הטיפוס כיתה ‪ ,StudentClass‬בהנחה שהטיפוסים תלמיד – ‪ ,Student‬ו מורה – ‪ Teacher‬מוגדרים‪.‬‬
‫במהלך הגדרת הטיפוס ניתן דגשים באשר לעצמים המשמשים כערך של תכונה‪ ,‬כערך של פרמטר‪ ,‬או‬
‫כערך מוחזר‪ .‬דיאגרמת המחלקות שמשתתפות בפרויקט זה היא‪:‬‬
‫‪Student‬‬
‫‪Teacher‬‬
‫‪School‬‬
‫‪StudentClass‬‬
‫תרשים ‪ UML‬של המחלקה ‪StudentClass‬‬
‫‪StudentClass‬‬
‫‪private char level‬‬
‫‪private int number‬‬
‫‪private Teacher educator‬‬
‫‪private int numOfStudents‬‬
‫‪private Student[] students‬‬
‫עיצוב תוכנה – טיפוס מורכב‬
‫©‬
‫כל הזכויות שמורות ל'מבט לחלונות'‬
‫‪11‬‬
‫‪public StudentClass(char level, int number, Teacher educator, int numOfStudents,‬‬
‫)‪Student[] students‬‬
‫)‪public StudentClass(char level, int number‬‬
‫)(‪public StudentClass‬‬
‫)(‪public char getLevel‬‬
‫)(‪public int getNumber‬‬
‫)(‪public Teacher getEducator‬‬
‫)(‪public int getNumOfStudents‬‬
‫)(‪public Student[] getStudents‬‬
‫)‪public void setLevel(char level‬‬
‫)‪public void setNumber(int number‬‬
‫)‪public void setEducator(Teacher educator‬‬
‫)‪public void setNumOfStudents(int numOfStudents‬‬
‫)‪public void setStudents(Student[] students‬‬
‫)(‪public Student bestInClass‬‬
‫)‪public boolean isStudentInClass(Student stu‬‬
‫הגדרת התכונות‬
‫הגדרת תכונה שהיא מטיפוס אחר של המשתמש מתבצעת בדיוק כמו הגדרה של כל תכונה אחרת‪.‬‬
‫תחילה מופיע טיפוס התכונה ואחר כך השם שלה‪.‬‬
‫‪public class StudentClass‬‬
‫הגדרת תכונות המחלקה ‪StudentClass‬‬
‫{‬
‫;‪char level‬‬
‫;‪int number‬‬
‫;‪Teacher educator‬‬
‫;‪int numOfStudents = 0‬‬
‫;]‪Student[] students = new Student[30‬‬
‫}‬
‫הסבר‪ :‬התכונה מחנך – ‪ ,educator‬היא מטיפוס מורה ‪ .Teacher -‬הערך של התכונה יהיה עצם‬
‫מטיפוס מורה‪ .‬בהמשך נראה כיצד תכונה זו מקבלת את הערך שלה‪.‬‬
‫התכונה תלמידים – ‪ ,students‬היא מערך של עצמים מטיפוס תלמיד – ‪ .Student‬במקרה זה‪ ,‬בהגדרת‬
‫התכונה נבנו גם ‪ 30‬תאי המערך‪ ,‬כלומר‪ ,‬בכיתה יכולים להיות עד ‪ 30‬תלמידים‪ .‬מאחר ולא בכל כיתה‬
‫יש מספר תלמידים זהה‪ ,‬מוגדרת גם התכונה מספר תלמידים בכיתה – ‪ .numOfStudents‬תכונה זו‬
‫מייצגת את מספר התלמידים בכיתה מסוימת‪ .‬הערך של התכונה הזו ינוהל כולו על ידי הפעולות‬
‫בטיפוס זאת מאחר והוא חייב להיות תואם לתלמידים המושמים במערך התלמידים‪.‬‬
‫עצמים כערכים של תכונות‬
‫ערכים של משתנים שהם מטיפוס של המשתמש הם עצמים ועל משתנים אלו ניתן להפעיל את‬
‫הפעולות המוגדרות בטיפוס שלהם‪ .‬עצם מטיפוס נקרא גם מופע של הטיפוס‪.‬‬
‫לדוגמה במחלקה ראשית ‪ TestStudent‬ניתן להגדיר מערך של עצמים מטיפוס ‪:Student‬‬
‫;]‪Student[] stu = new Student[30‬‬
‫‪12‬‬
‫עיצוב תוכנה – טיפוס מורכב‬
‫©‬
‫כל הזכויות שמורות ל'מבט לחלונות'‬
‫בדיוק באותו אופן מגדירים ומשתמשים בתכונות שהן מטיפוס של המשתמש‪ ,‬שהערכים שלהן הם‬
‫עצמים‪ .‬למשל בגוף הפעולה הבונה )‪ StudentsClass(….‬תהיה השמה לתכונה ‪:students‬‬
‫;‪this.students = students‬‬
‫הכללים שהותוו לגבי תכונות של טיפוס פשוט זהים גם לתכונות מטיפוס מורכב‪ .‬גם לתכונות אלו‬
‫תוגדרנה פעולה קובעת ופעולה מאחזרת למשל פעולה מאחזרת ופעולה קובעת למורה של כיתה‪:‬‬
‫)(‪public Teacher getEducator‬‬
‫{‬
‫;‪return educator‬‬
‫}‬
‫)‪public void setEducator(Teacher educator‬‬
‫{‬
‫;‪this.educator = educator‬‬
‫}‬
‫בכל מקרה ההתייחסות למשתנה‪/‬תכונה‪/‬פרמטר מטיפוס בסיסי כמו ‪ int‬שהערך שלו הוא מספר שלם‬
‫כלשהו‪ ,‬זהה להתייחסות למשתנה‪/‬תכונה‪/‬פרמטר שהוא מטיפוס ‪ Student‬שהערך שלו הוא עצם‬
‫מטיפוס זה‪ .‬כלומר‪ ,‬פרמטרים המועברים לפעולות וגם ערכים המוחזרים על ידי פעולות‪ ,‬יכולים‬
‫להיות מטיפוס של המשתמש ויכילו עצמים‪ .‬בסעיפים הבאים נסביר ונדגים את השימושים‬
‫האפשריים בתכונה שהיא מטיפוס של המשתמש והערך שלה הוא עצם‪.‬‬
‫העצם הנוכחי ‪this -‬‬
‫כל פעולה המוגדרת בטיפוס המייצג ישות תופעל על עצם מן הטיפוס‪ .‬לפעמים יש צורך להתייחס אל‬
‫העצם הנוכחי עליו מופעלת הפעולה‪ .‬במקרה זה משתמשים במילה השמורה ‪ .this‬אין הכרח להשתמש‬
‫בה אך מקובל להשתמש בה במקומות שיוסברו להלן‪.‬‬
‫פעולות בונות ופעולות קובעות מקבלות פרמטרים שמטרתם להעביר ערכים לאתחול‪/‬עדכון של‬
‫תכונות‪ .‬מקובל להשתמש בפרמטר שיש לו שם זהה לשם התכונה‪ .‬למשל אם התכונה היא ‪number‬‬
‫הפרמטר שצריך לעדכן אתה יהיה אף הוא ‪.number‬‬
‫אם כך משפט ההשמה יהיה ;‪? number = number‬‬
‫במקרה של הגדרה כזו הקומפיילר מתייחס למשתנה ‪ number‬שהוגדר כפרמטר משני צידי משפט‬
‫ההשמה ולא יתייחס כלל לתכונה‪ .‬אם רוצים להתייחס אל התכונה יש לומר שמתייחסים ל ‪number‬‬
‫של העצם הנוכחי‪.‬‬
‫;‪this.number = number‬‬
‫משפט ההשמה של ערך הפרמטר לתכונה יוגדר אם כן כך‪:‬‬
‫מצד שמאל של משפט ההשמה ‪ – this.number‬מתייחס אל התכונה ‪ number‬של העצם הנוכחי‪,‬‬
‫כלומר‪ ,‬העצם עליו מופעלת הפעולה‪ .‬מצד ימין של משפט ההשמה ‪ – number‬מתייחס אל הפרמטר‬
‫‪.number‬‬
‫בספר זה יהיה שימוש בפניה לעצם הנוכחי ‪ this‬רק במקרים אלה‪.‬‬
‫עד כה ראינו את סימן הנקודה ( ‪ )dot notation‬עבור הפעלת פעולה על עצם‪ .‬גם כאן השימוש בסימן‬
‫הנקודה מתייחס לעצם – לעצם הנוכחי הסמוי‪ ,‬אך הפנייה היא לתכונה ולא לצורך הפעלת פעולה‪.‬‬
‫עיצוב תוכנה – טיפוס מורכב‬
‫©‬
‫כל הזכויות שמורות ל'מבט לחלונות'‬
‫‪13‬‬
‫בטיפוס מורכב נגדיר פעולות לפי אותן קטגוריות שתוארו בטיפוס פשוט‪:‬‬
‫‪ ‬פעולות בונות – עמוד ‪14‬‬
‫‪ ‬פעולות מאחזרות – עמוד ‪16‬‬
‫‪ ‬פעולות קובעות – עמוד ‪16‬‬
‫‪ ‬פעולות חישוביות המחזירות עצם – עמוד ‪17‬‬
‫‪ ‬פעולות חישוביות המקבלות עצם כפרמטר – עמוד ‪18‬‬
‫פעולות בונות‬
‫פעולה בונה היא פעולה שתמיד מחזירה עצם חדש‪ .‬השלבים המתבצעים בהפעלת פעולה בונה הם‪:‬‬
‫‪ )1‬הקצאת שטחי זיכרון לעצם בהתאם להגדרת התכונות שלו ולטיפוסים שלהן‪.‬‬
‫‪ )2‬אתחול ערכי כל התכונות בערכי ברירת המחדל על פי הטיפוסים שלהם‪.‬‬
‫‪ )3‬ביצוע גוף הפעולה הבונה‪ .‬אם גוף הפעולה הבונה כולל השמת ערכים חדשים לתכונות הם‬
‫כמובן מתעדכנים‪.‬‬
‫‪ )4‬החזרת העצם שנבנה (למעשה החזרת הפנייה אל העצם החדש)‪.‬‬
‫פעולה בונה בטיפוס מורכב תוגדר באותו אופן בו הוגדרה עבור טיפוס פשוט‪ .‬התבנית הסטנדרטית של‬
‫הפעולה הבונה היא זו המקבלת פרמטר עבור כל אחת מן התכונות שלה‪ ,‬ומשימה את ערכי‬
‫הפרמטרים להיות ערכי התכונות‪.‬‬
‫לדוגמה הגדרת פעולה בונה בטיפוס כיתה המקבלת פרמטר לכל תכונה‪:‬‬
‫‪public StudentClass(char level, int number, Teacher educator, int numOfStudents,‬‬
‫)‪Student[] students‬‬
‫{‬
‫;‪this.level = level‬‬
‫;‪this.number = number‬‬
‫;‪this.educator = educator‬‬
‫;‪this.numOfStudents = numOfStudents‬‬
‫הסבר‬
‫הפתרון‬
‫;‪this.students = students‬‬
‫}‬
‫הסבר‪ :‬הפרמטר ‪ educator‬הוא מטיפוס ‪ Teacher‬ובגוף הפעולה הוא מושם לתכונה ‪ educator‬שהיא‬
‫מטיפוס ‪ .Teacher‬הפרמטר ‪ students‬הוא מטיפוס מערך של סטודנטים ][‪ ,Student‬והוא מושם‬
‫לתכונה ‪ students‬שאף היא מן הטיפוס מערך של סטודנטים ][‪.Student‬‬
‫ניתן להגדיר במחלקה מספר פעולות בונות ובלבד שרשימת הפרמטרים שלהם תהיה מובחנת‪ ,‬כלומר‪,‬‬
‫לא יכולות להיות שתי פעולות בונות שיש להן פרמטרים מאותם טיפוסים ובאותו הסדר‪ .‬די שיהיה‬
‫שינוי אחד‪ ,‬למשל‪ :‬בטיפוס של פרמטר‪ ,‬במספר הפרמטרים או בסדר הפרמטרים הכולל שינוי בסדר‬
‫הטיפוסים שלהם‪ .‬ניתן להגדיר פעולה בונה נוספת שמשימה ערכים מפרמטרים רק לחלק מן התכונות‬
‫ויתר הערכים של התכונות יקבעו תחילה על ידי ערכי ברירת מחדל‪ ,‬ומאוחר יותר לפי הצורך על ידי‬
‫פעולות קובעות או פעולות חישוביות אחרות‪.‬‬
‫‪14‬‬
‫עיצוב תוכנה – טיפוס מורכב‬
‫©‬
‫כל הזכויות שמורות ל'מבט לחלונות'‬
‫לדוגמה פעולה בונה נוספת בטיפוס כיתה המקבלת רק שני פרמטרים‪:‬‬
‫)‪public StudentClass(char level, int number‬‬
‫{‬
‫;‪this.level = level‬‬
‫;‪this.number = number‬‬
‫}‬
‫פעולה בונה מעתיקה‬
‫חושבים‬
‫רגע‪..‬‬
‫כיצד נקבל העתק של עצם?‬
‫כאשר אנו משתמשים בטיפוסים בסיסיים ויש צורך במשתנה נוסף עם אותו ערך‪ ,‬פשוט‬
‫מבצעים השמה‪ .‬נעקוב אחר קטע הקוד הבסיסי שלהלן‪:‬‬
‫הוראה‬
‫‪x‬‬
‫‪y‬‬
‫הסבר‪ :‬אחרי ההשמה של ערך ‪ x‬ל‪ y ,y -‬הוא‬
‫‪8‬‬
‫;‪int x = 8‬‬
‫העתק של ‪ – x‬בשניהם יש את אותו ערך‪ .‬שינוי‬
‫‪8‬‬
‫‪8‬‬
‫;‪int y = x‬‬
‫של ‪ x‬לאחר מכן לא משנה את ‪.y‬‬
‫‪9‬‬
‫‪8‬‬
‫;‪x = 9‬‬
‫מה קורה ביחס לעצמים? למשל ביחס לעצמים מן הטיפוס ‪ .Song‬נסתכל על אותו רצף של הוראות‪:‬‬
‫;)‪Song sx = new Song("Jerusalem", "Yael", 190‬‬
‫;‪Song sy = sx‬‬
‫;)‪sx.setLength(200‬‬
‫מה אורך השיר ‪ ?sx‬מה אורך השיר ‪?sy‬‬
‫‪sx: Song‬‬
‫נעקוב אחר הקצאת הזיכרון עבור העצמים‪:‬‬
‫בעקבות ההוראה‪Song sx = new Song("Jerusalem", "Yael", 190); :‬‬
‫תתקבל תמונת הזיכרון הבאה‪:‬‬
‫‪Jerusalem‬‬
‫‪Yael‬‬
‫‪190‬‬
‫‪sy: Song‬‬
‫;‪Song sy = sx‬‬
‫בעקבות ההוראה‪:‬‬
‫תתקבל תמונת הזיכרון הבאה‪:‬‬
‫‪performer:‬‬
‫‪length:‬‬
‫‪sx: Song‬‬
‫‪Jerusalem:‬‬
‫‪Yael‬‬
‫‪200‬‬
‫‪name:‬‬
‫‪name:‬‬
‫‪performer:‬‬
‫‪length:‬‬
‫כלומר הוקצה משתנה ‪ sy‬מטיפוס ‪ Song‬אך הוא הפנייה – לא נבנה עצם חדש‪ ,‬לא הוקצו שטחי‬
‫זיכרון חדשים‪ sx, sy .‬מפנים אל אותו עצם‪.‬‬
‫לכן לאחר ביצוע קביעה של ערך חדש לאורך השיר ‪ ,sx‬העדכון חל גם על ‪ sy‬כי זה אותו העצם‪.‬‬
‫כלומר‪ :‬ההוראה ;)‪ sx.setLength(200‬תעדכן את ערך התכונה שהוא משותף ל‪ sx, sy -‬כי הם רק‬
‫הפניות שונות אל אותו עצם!!! לכן‪ ,‬אם רוצים ליצור עותק עצמאי של עצם יש צורך לבנות אותו ע"י‬
‫פעולה בונה‪ ,‬אחרת לא יוקצו עבורו שטחי זיכרון חדשים‪.‬‬
‫פעולה בונה מעתיקה היא פעולה בונה המקבלת עצם מאותו הטיפוס ומחזירה עצם חדש (שטחי זיכרון‬
‫חדשים) אשר ערכי התכונות שלו זהים לערכי התכונות של העצם בפרמטר‪.‬‬
‫עבור הטיפוס ‪ Song‬נגדיר את הפעולה הבונה המעתיקה הבאה‪:‬‬
‫עיצוב תוכנה – טיפוס מורכב‬
‫©‬
‫כל הזכויות שמורות ל'מבט לחלונות'‬
‫‪15‬‬
‫שים ‪ :‬אין בעיה שפעולה בונה במחלקה‬
‫‪ Song‬תקבל כפרמטר עצם מאותה המחלקה‪.‬‬
‫באופן דומה ניתן להגדיר פעולה בונה מעתיקה‬
‫גם עבור טיפוס מורכב‪.‬‬
‫)‪public Song(Song s‬‬
‫{‬
‫;)(‪this.name = s.getName‬‬
‫;)(‪this.performer = s.getPerformer‬‬
‫;)(‪this.length = s.getLength‬‬
‫}‬
‫העמסת פעולות‬
‫הדוגמאות שהוצגו עבור הגדרות שונות לפעולה מתאפשרות עקב המנגנון של העמסת פעולות‬
‫(‪ .)methods overload‬מאחר ויש הבחנה בכותרת של הפעולות‪ ,‬הבאה לידי ביטוי ברשימת‬
‫הפרמטרים שלה‪ ,‬הפעולות יכולות להיות בעלות שם זהה‪ .‬מנגנון זה פועל ביחס לכל סוגי הפעולות‬
‫המוגדרות ולא רק ביחס לפעולה בונה‪.‬‬
‫פעולות מאחזרות‬
‫השימוש בערכים שהם עצמים זהה לשימוש בכל ערך אחר‪ .‬כפי שפעולה יכולה להחזיר ערך מטיפוס‬
‫‪ Student‬או מטיפוס‬
‫‪ int‬או ‪ boolean‬או ‪ ,String‬היא יכולה להחזיר ערך שהוא עצם מטיפוס‬
‫‪ Teacher‬או מטיפוס ‪ .StudentClass‬בהתאם לכלל המקובל יש להגדיר פעולה מאחזרת לכל תכונה‪,‬‬
‫בין אם התכונה מטיפוס פשוט ובין אם טיפוס התכונה מטיפוס שהוגדר על ידי המשתמש‪ .‬במקרה‬
‫שהתכונה מטיפוס שהוגדר על ידי המשתמש‪ ,‬יוחזר עצם שהוא הערך של התכונה‪.‬‬
‫נסתכל לדוגמה על מספר פעולות מאחזרות שניתן להגדיר בטיפוס כיתה‪:‬‬
‫הפעולה ומשמעותה‬
‫מטרת הפעולה‪ :‬הפעולה מאחזרת את ערך התכונה מחנך‪.‬‬
‫הסבר‪ :‬טיפוס הערך המוחזר על ידי הפעולה הוא ‪Teacher‬‬
‫כטיפוס התכונה ‪ .educator‬כלומר מוחזר עצם מטיפוס מורה‪.‬‬
‫מטרת הפעולה‪ :‬הפעולה מאחזרת את ערך התכונה מערך‬
‫תלמידים‪ .‬הסבר‪ :‬טיפוס הערך המוחזר על ידי הפעולה הוא‬
‫][‪ Student‬כטיפוס התכונה ‪ .students‬כלומר מוחזר עצם מטיפוס‬
‫מערך תלמידים‪.‬‬
‫קוד הפעולה‬
‫)(‪public Teacher getEducator‬‬
‫{‬
‫;‪return educator‬‬
‫}‬
‫)(‪public Student[] getStudents‬‬
‫{‬
‫;‪return students‬‬
‫}‬
‫פעולות קובעות‬
‫מטרת פעולה קובעת היא לקבוע ערך לתכונה‪ .‬באותו אופן בו הפעולה הבונה שהוגדרה לעיל קיבלה‬
‫פרמטר שהערך שלו הוא עצם והשימה אותו בתכונה המתאימה‪ ,‬תוגדר גם הפעולה הקובעת‬
‫המתאימה לתכונה‪ .‬נסתכל לדוגמה על מספר פעולות קובעות שניתן להגדיר בטיפוס כיתה‪:‬‬
‫קוד הפעולה‬
‫הפעולה ומשמעותה‬
‫מטרת הפעולה‪ :‬הפעולה קובעת את ערך התכונה מורה‪.‬‬
‫הסבר‪ :‬טיפוס הפרמטר הוא ‪ Teacher‬כטיפוס התכונה‬
‫‪ educator‬שאת הערך שלה קובעת הפעולה‪ ,‬כלומר‪,‬‬
‫מושם בתכונה עצם (כמוסה) מטיפוס מורה‪.‬‬
‫מטרת הפעולה‪ :‬הפעולה קובעת את ערך התכונות‪:‬‬
‫‪16‬‬
‫עיצוב תוכנה – טיפוס מורכב‬
‫©‬
‫‪public void setEducator(Teacher‬‬
‫)‪educator‬‬
‫{‬
‫;‪this.educator = educator‬‬
‫}‬
‫][‪public void setStudents(Student‬‬
‫כל הזכויות שמורות ל'מבט לחלונות'‬
‫מספר תלמידים בכיתה ומערך התלמידים בכיתה‪.‬‬
‫הסבר‪ :‬טיפוס הפרמטר עבור מערך תלמידי הכיתה הוא‬
‫][‪ Student‬כטיפוס התכונה ‪ students‬שאת הערך שלה‬
‫הפעולה קובעת‪ .‬כלומר מושם בתכונה עצם מטיפוס‬
‫מערך תלמידים‪.‬‬
‫)‪students, int numOfStudents‬‬
‫{‬
‫;‪this.students = students‬‬
‫;‪this.numOfStudents=numOfStudents‬‬
‫}‬
‫פעולות קובעות ומאחזרות – הרחבה‬
‫נהוג להגדיר פעולה קובעת ומאחזרת לכל תכונה כך שתהיה גישה לתכונות ע"י פעולות ולא באופן‬
‫ישיר‪ .‬נוהג זה הוא יישום של עקרון הסתרת המידע הבא לידי ביטוי בשני מובנים‪ )1 ( :‬הסתרת הייצוג‬
‫הפנימי‪ )2 ( ,‬מתן אחריות למפתח מחלקה להחליט לאילו תכונות יש גישה לצורך אחזור ו‪/‬או עדכון‪.‬‬
‫למשל‪ :‬אם מחלקה מממשת משחק ניחושים של ערך שלם‪ ,‬לא תהיה גישה לאחזור הערך אותו יש‬
‫לנחש; אם מחלקה מממשת ניהול שיחות טלפון לא תהיה אפשרות למשתמש במחלקה לשנות את זמן‬
‫תחילת השיחה‪ .‬כלומר‪ :‬למרות הכלל להגדיר פעולה מאחזרת וקובעת לכל תכונה – מפתח מחלקה‬
‫מפעיל שיקול דעת ויכול להסיר חלק מהן בהתאם לצורך‪.‬‬
‫לעיתים יש צורך בפעולות שהן מאחזרות או קובעות לא עבור תכונה אלא עבור חלק ממנה‪ .‬דוגמה‬
‫טובה לכך היא בשימוש במערכים‪ .‬למשל בפעולה הבאה או בפעולות המופיעות להלן בתרגילים ‪:4 ,3‬‬
‫הפעולה ומשמעותה‬
‫קוד הפעולה‬
‫מטרת הפעולה‪ :‬הפעולה מוסיפה תלמיד לכיתה‪ .‬הנחה‪:‬‬
‫מספר התלמידים בכיתה קטן מן המקסימום האפשרי‪.‬‬
‫הסבר‪ :‬טיפוס הפרמטר הוא ‪ Student‬כטיפוס תא‬
‫במערך התלמידים המיוצג בתכונה ‪ ,students‬אליו‬
‫מוסיפים תלמיד‪ .‬כדי להוסיף את התלמיד יש להשים‬
‫בתא המערך המתאים את התלמיד החדש ולקדם את‬
‫התכונה המייצגת את מספר התלמידים בכיתה ב‪.1-‬‬
‫)‪public void addStudent(Student stu‬‬
‫{‬
‫;‪students[numOfStudents] = stu‬‬
‫;‪numOfStudents++‬‬
‫}‬
‫פעולות חישוביות המחזירות עצם‬
‫חושבים‬
‫פעולות חישוביות יכולות להחזיר עצמים בדומה לפעולות המאחזרות‪ .‬לדוגמה פעולה בטיפוס כיתה‬
‫המחזירה את התלמיד בעל ממוצע הציונים הגבוה ביותר (בהנחה שיש רק תלמיד אחד כזה)‪:‬‬
‫)(‪public Student bestInClass‬‬
‫{‬
‫;)(‪int maxAverage = students[0].average‬‬
‫;‪int p = 0‬‬
‫;‪int average‬‬
‫)‪for (int i = 1 ; i<numOfStudents ; i++‬‬
‫{‬
‫;)(‪average = students[i].average‬‬
‫)‪if (average>maxAverage‬‬
‫{‬
‫;‪maxAverage = average‬‬
‫;‪p = i‬‬
‫רגע‪..‬‬
‫}‬
‫}‬
‫;]‪return students[p‬‬
‫}‬
‫עיצוב תוכנה – טיפוס מורכב‬
‫©‬
‫כל הזכויות שמורות ל'מבט לחלונות'‬
‫‪17‬‬
‫הסבר‬
‫הפתרון‬
‫הסבר‪ :‬הפעולה תופעל על עצם מטיפוס כיתה‪ .‬הפעולה לא צריכה לקבל פרמטרים לצורך ביצוע‬
‫משימת החישוב שלה‪ .‬בגוף הפעולה נסרק מערך התלמידים‪ .‬המשתנה ‪ maxAverage‬מכיל את‬
‫הממוצע הגבוה ביותר שהתקבל עד כה והמציין ‪ p‬הוא מציין המכיל בהתאמה את מספר תא‬
‫המערך בו נמצא התלמיד עם הממוצע הגבוה ביותר‪ .‬בתום סריקת המערך מוחזר התלמיד‬
‫המתאים מתוך מערך התלמידים – התלמיד ]‪ .students[p‬הערך המוחזר על‪-‬ידי הפעולה הוא עצם‬
‫מטיפוס תלמיד‪ .‬עובדה זו באה לידי ביטוי בשני מקומות‪ :‬האחד‪ ,‬בהגדרת טיפוס הערך המוחזר‬
‫‪ Student‬המופיע בכותרת הפעולה‪ .‬השני‪ ,‬מאחר והמערך ‪ students‬הוא מערך של תלמידים אזי‬
‫תא המערך ]‪ students[p‬הוא תלמיד‪ .‬שים ‪ :‬מאחר וכל תא במערך הוא מטיפוס תלמיד‪ ,‬ניתן‬
‫להפעיל על עצם מטיפוס תלמיד את הפעולה )(‪ average‬המוגדרת בטיפוס תלמיד‪ .‬למשל‪ ,‬הזימון‬
‫)(‪ students[i].average‬מחזיר את ממוצע הציונים של התלמיד שנמצא במערך במקום ‪.i‬‬
‫יתרון משמעותי של המודולאריות‪ ,‬שהיא אחד מעקרונות היסוד של תכנות מונחה עצמים‪ ,‬הוא‬
‫אי‪-‬תלות בייצוג של התכונות‪ .‬למשל‪ ,‬בפרק ‪ ,7‬עודכנו התכונות בטיפוס תלמיד כך שהציונים יהיו‬
‫במערך של ציונים ולא רק ציונים ב‪ 3 -‬מקצועות‪ .‬בהתאמה הוגדרה שם גם פעולה המחשבת את‬
‫הממוצע שחתימתה זהה )(‪ .average‬כלומר‪ ,‬גם אם בפרויקט ישולב הטיפוס ‪ Student‬המקורי‪,‬‬
‫או הטיפוס ‪ Student‬המורחב למערך ציונים‪ ,‬לא יהיה צורך לשנות דבר בטיפוס כיתה המוגדר‬
‫כאן‪.‬‬
‫פעולות חישוביות המקבלות עצם כפרמטר‬
‫הסבר‬
‫הפתרון‬
‫פעולות חישוביות יכולות לקבל פרמטרים שהערכים שלהם הם עצמים‪ ,‬בדומה לפעולות הקובעות‬
‫המקבלות פרמטר שהוא עצם‪ .‬לדוגמה‪ ,‬פעולה בטיפוס כיתה המקבלת תלמיד ‪ stu‬ומחזירה אמת אם‬
‫התלמיד נמצא בכיתה זו או שקר אם הוא לא נמצא בכיתה זו‪ .‬ההשוואה מתבצעת על פי ת‪.‬ז‪.‬‬
‫)‪public boolean isStudentInClass(Student stu‬‬
‫{‬
‫)‪for (int i=0 ; i<numOfStudents ; i++‬‬
‫{‬
‫)))(‪if (students[i].getIdNum().equals(stu.getIdNum‬‬
‫;‪return true‬‬
‫}‬
‫;‪return false‬‬
‫}‬
‫הסבר‪ :‬הפעולה תופעל על עצם מטיפוס כיתה שיש לו את התכונה ‪ - students‬מערך של תלמידים‪.‬‬
‫הפעולה סורקת את מערך התלמידים בהתאם למספר התלמידים הנמצא בתכונה ‪numOfStudents‬‬
‫ובודקת האם התלמיד במקום ‪ i‬במערך הוא התלמיד שמספר ת‪.‬ז‪ .‬שלו זהה לתלמיד ‪ stu‬שהתקבל‬
‫בפרמטר‪ .‬אם מספר ת‪.‬ז‪ .‬נמצא מוחזר הערך אמת‪ ,‬אחרת בתום סריקת המערך מוחזר הערך שקר‪.‬‬
‫נסביר בהרחבה את הביטוי הבוליאני‪students[i].getIdNum().equals(stu.getIdNum()) :‬‬
‫על התלמיד ‪stu‬‬
‫הפעל את הפעולה‪:‬‬
‫אחזר מספר ת‪.‬ז‪.‬‬
‫‪18‬‬
‫עיצוב תוכנה – טיפוס מורכב‬
‫על התלמיד מספר ‪i‬‬
‫במערך התלמידים‬
‫הפעל את הפעולה‪:‬‬
‫אחזר מספר ת‪.‬ז‪.‬‬
‫הפעל את הפעולה ‪equals‬‬
‫לבדוק האם שני מספרי תעודות‬
‫הזהות (שהם מחרוזות) ‪ -‬זהים‬
‫©‬
‫כל הזכויות שמורות ל'מבט לחלונות'‬
‫כתוב פעולה‬
‫תרגילים לטיפוס מורכב‪ :‬פעולות‬
‫‪‬‬
‫תרגיל ‪ :1‬הגדרת פעולה בונה נוספת בטיפוס כיתה‬
‫בהנחה שבטיפוס ‪ Teacher‬יש פעולה בונה שהחתימה שלה‪Teacher(String name, String id) :‬‬
‫המקבלת שם ו‪-‬ת‪.‬ז‪ .‬של מורה‪ .‬כתוב פעולה בונה בטיפוס ‪ StudentClass‬המקבלת כפרמטרים את‪:‬‬
‫השכבה של הכיתה‪ ,‬מספר הכיתה‪ ,‬מספר התלמידים בכיתה‪ ,‬שם המחנך של הכיתה ות‪.‬ז‪ .‬של המחנך‪.‬‬
‫הפעולה תאתחל בהתאמה את התכונות‪ :‬שכבה‪ ,‬מספר כיתה‪ ,‬מספר תלמידים בכיתה ומחנך הכיתה‪.‬‬
‫‪‬‬
‫תרגיל ‪ :2‬הגדרת פעולה בונה מעתיקה‬
‫הגדר במחלקה ‪ StudentClass‬פעולה בונה מעתיקה‪.‬‬
‫שים ‪ :‬הפעולה מקבלת עצם מטיפוס ‪.StudentClass‬‬
‫תרגיל ‪ :3‬הגדרת פעולה מאחזרת בטיפוס כיתה ‪‬‬
‫‪ n‬במערך‬
‫‪ n‬ומחזירה את התלמיד שמיקומו‬
‫הגדר בטיפוס כיתה פעולה המקבלת מספר שלם‬
‫התלמידים‪ .‬הנח כי המספר ‪ n‬תקין ובטווח של מספר התלמידים בכיתה‪ .‬שים לב שהפעולה מחזירה‬
‫ערך מטיפוס תלמיד‪.‬‬
‫תרגיל ‪ :4‬הגדרת פעולה קובעת בטיפוס כיתה ‪‬‬
‫חושבים‬
‫הגדר בטיפוס כיתה פעולה המקבלת מספר שלם ‪ n‬ותלמיד ‪ stu‬ו קובעת את התלמיד להיות במקום ‪n‬‬
‫במערך התלמידים‪ .‬הנח כי המספר ‪ n‬תקין ובטווח של מספר התלמידים בכיתה‪.‬‬
‫רגע‪..‬‬
‫שאלה למחשבה‪ :‬אם במקום ‪ n‬במערך התלמידים כבר נמצא תלמיד (עצם מטיפוס ‪)Student‬‬
‫מה קורה לו?‬
‫תרגיל ‪ :5‬הגדרה של פעולה המחזירה עצם בטיפוס כיתה ‪‬‬
‫הגדר בטיפוס כיתה פעולה המקבלת מחרוזת שהיא מספר ת‪.‬ז‪ ,.‬ומחזירה את התלמיד בעל ת‪.‬ז‪ .‬זו‬
‫מבין תלמידי הכיתה‪ .‬שים לב שטיפוס התכונה ת‪.‬ז‪ .‬הוא מחרוזת‪ .‬הנחה‪ :‬תלמיד עם ת‪.‬ז‪ .‬זו נמצא‬
‫בכיתה‪.‬‬
‫תרגיל ‪ :6‬הגדרה של פעולה בטיפוס כיתה המקבלת עצם כפרמטר ‪‬‬
‫‪‬‬
‫הגדר בטיפוס כיתה פעולה המקבלת עצם מטיפוס מורה ובודקת האם הוא המחנך של הכיתה‪ .‬אם כן‬
‫תחזיר הפעולה אמת‪ ,‬ואם לא תחזיר שקר‪.‬‬
‫עיצוב תוכנה – טיפוס מורכב‬
‫©‬
‫כל הזכויות שמורות ל'מבט לחלונות'‬
‫‪19‬‬
‫מחלקה ראשית אינה מייצגת טיפוס נתונים כמו תלמיד או שיר או כיתה או רובוט‪ ,‬אלא מחלקה בה‬
‫מתבצעת משימה‪ .‬במחלקה זו מוגדרים העצמים ומופעלות עליהם פעולות‪ .‬בדומה למחלקה הראשית‬
‫בה בנינו עצמים מטיפוס של המשתמש (פרק ‪ 6‬ביסודות חלק ב)‪ ,‬ובדומה להגדרת מערך של עצמים‬
‫(פרק ‪ 7‬ביסודות חלק ב)‪ ,‬נגדיר מחלקה ראשית שבפעולה הראשית שלה מוגדרים משתנים מטיפוס‬
‫מורכב‪ .‬אין כל שינוי בעקרונות הפיתוח של המחלקה הראשית‪.‬‬
‫‪‬‬
‫דוגמה‬
‫פתורה‬
‫דוגמה למחלקה ראשית המגדירה עצמים מטיפוס מורכב‬
‫נגדיר מחלקה ראשית ‪ .Test‬יחד עם מחלקה זו קיימים בפרויקט הטיפוסים‪ ,Teacher ,Student :‬ו‪-‬‬
‫‪ .StudentClass‬הטיפוסים מוגדרים בהתאם לתרשימי ה‪ UML -‬בתחילת הפרק‪ .‬בפעולה הראשית של‬
‫המחלקה ‪ Test‬מתבצע האלגוריתם הבא‪:‬‬
‫‪ )1‬בנה מורה חדש ע"י שימוש בפעולה הבונה )(‪ Teacher‬והשם אותו במשתנה ‪.teacher‬‬
‫‪ )2‬בנה כיתה ע"י שימוש בפעולה הבונה )(‪ StudentClass‬לתוך ‪.stuClass‬‬
‫‪ )3‬בדוק והדפס הודעה מתאימה‪ ,‬אם המורה ‪ teacher‬הוא המחנך של הכיתה ‪.stuClass‬‬
‫‪ )4‬קלוט ת‪.‬ז‪ .‬של תלמיד‪ ,‬הלומד בכיתה והדפס את התעודה שלו‪.‬‬
‫‪ )5‬הדפס את התעודה של התלמיד המצטיין בכיתה ‪.stuClass‬‬
‫מימוש המחלקה הראשית בשפת התכנות‪:‬‬
‫‪public class Test‬‬
‫{‬
‫;)‪public static Scanner reader = new Scanner(System.in‬‬
‫‪ */‬הפעולה הראשית **‪/‬‬
‫)‪public static void main(String[] args‬‬
‫{‬
‫;)(‪Teacher teacher = new Teacher‬‬
‫;)(‪StudentClass stuClass = new StudentClass‬‬
‫) )‪if ( stuClass.isEducator(teacher‬‬
‫;)"‪System.out.println("The teacher is the class educator‬‬
‫‪else‬‬
‫;)"‪System.out.println ("The teacher is not the class educator‬‬
‫;)(‪String number = reader.next‬‬
‫;)(‪stuClass.findStudent(number).printCertificate‬‬
‫;)(‪stuClass.bestInClass().printCertificate‬‬
‫דוגמה‬
‫}‬
‫פתורה‬
‫}‬
‫‪‬‬
‫דוגמה פתורה‪ :‬הטיפוס דיסק‬
‫בסעיף זה מוצג פרויקט הכולל שלושה טיפוסים‪ :‬הטיפוס שיר‬
‫הממומש במחלקה ‪ Song‬שהוצג בפרק ‪ 6‬בספר יסודות חלק ב‪,‬‬
‫הטיפוס המורכב דיסק הממומש במחלקה ‪ Disc‬שתפותח כאן‪,‬‬
‫והמחלקה הראשית ‪ TestDisc‬שתפותח כאן‪.‬‬
‫‪20‬‬
‫עיצוב תוכנה – טיפוס מורכב‬
‫©‬
‫‪Song‬‬
‫‪Disc‬‬
‫‪TestDisc‬‬
‫כל הזכויות שמורות ל'מבט לחלונות'‬
‫תיאור הטיפוס שיר‬
‫הטיפוס שיר ( ‪ )Song‬מאפיין שירים ומתייחס אל שלוש תכונות‪ :‬שם השיר‪ ,‬שם המבצע ואורך השיר‬
‫בשניות‪ .‬ניתן כמובן להוסיף תכונות נוספות‪ .‬האיור שלהלן מתאר את הטיפוס שיר וכולל הרחבה‬
‫בסיווג הפעולות‪ .‬כל הפעולות המופיעות באיור יופיעו בהגדרת המחלקה המממשת את הטיפוס‪:‬‬
‫הטיפוס‬
‫תכונות‬
‫פעולות‬
‫שיר‬
‫שם השיר‬
‫שם המבצע‬
‫אורך השיר בשניות‬
‫בונות‬
‫מאחזרות‬
‫קובעות‬
‫חישוביות‬
‫מימוש המחלקה ‪Song‬‬
‫תכונות‬
‫שיר (_שם‪_ ,‬מבצע‪_ ,‬אורך)‬
‫שיר ( ) { פעולה בונה הקולטת ערכים לתכונות }‬
‫אחזר שם שיר ( )‬
‫אחזר שם מבצע ( )‬
‫אחזר אורך ( )‬
‫קבע שם שיר (_שם‪) 1‬‬
‫קבע שם מבצע ( _מבצע‪) 1‬‬
‫קבע אורך (_אורך‪) 1‬‬
‫הגדל אורך שיר ב (_מספר_שניות)‬
‫הקטן אורך שיר ב (_מספר_שניות)‬
‫סיווג אורך ()‬
‫{ קצר‪ -‬קטן מ‪ 2-‬דקות‪,‬‬
‫ארוך‪ -‬ארוך מ‪ 4 -‬דקות‪,‬‬
‫ממוצע – אחרת }‬
‫הדפס פרטי שיר()‬
‫;*‪import java.util.‬‬
‫‪class Song‬‬
‫{‬
‫;)‪static Scanner s = new Scanner(System.in‬‬
‫‪// Name of song‬‬
‫‪// Name of the Performer of the song‬‬
‫‪// Length of song in seconds‬‬
‫פעולות‬
‫בונות‬
‫;‪private String name‬‬
‫;‪private String performer‬‬
‫;‪private int length‬‬
‫)‪Song(String name, String performer, int length‬‬
‫{‬
‫;‪this.name = name‬‬
‫;‪this.performer = performer‬‬
‫;‪this.length = length‬‬
‫}‬
‫)(‪Song‬‬
‫{‬
‫}‬
‫)(‪String getName‬‬
‫{‬
‫;‪return name‬‬
‫}‬
‫)(‪String getPerformer‬‬
‫{‬
‫;‪return performer‬‬
‫}‬
‫פעולות‬
‫מאחזרות‬
‫עיצוב תוכנה – טיפוס מורכב‬
‫©‬
‫כל הזכויות שמורות ל'מבט לחלונות'‬
‫‪21‬‬
int getLength()
{
return length;
}
void setName(String name)
{
this.name = name;
}
void setPerformer(String performer)
{
this.performer = performer;
}
void setLength(int length)
{
this.length = length;
}
‫פעולות‬
‫קובעות‬
/** ‫ שניות‬sec -‫* הפעולה מגדילה את אורך השיר ב‬/
void increaseLength(int sec)
‫פעולות‬
{
‫חישוביות‬
length = length + sec;
}
/** ‫ שניות‬sec -‫* הפעולה מקטינה את אורך השיר ב‬/
void decreaseLength(int sec)
{
length = length - sec;
}
/
** ‫* הפעולה מחזירה מחרוזת שהיא הקטגוריה של אורך השיר‬
* ‫ ממוצע‬- ‫ אחרת‬,‫ דקות – ארוך‬4 ‫ אם אורכו מעל‬,‫ דקות – קצר‬2 ‫* אם אורכו עד‬/
String category()
{
if (length< 2*60)
return "short";
else
if (length > 4*60)
return "long";
else
return "average";
}
/** ‫* הפעולה מדפיסה את תכונות השיר‬/
void displaySongDetails()
{
System.out.println("The song name is: " + name);
System.out.println("The preformer is: " + performer);
System.out.println("The song length in seconds is: " + length);
}
}
‫תיאור הטיפוס דיסק‬
-‫ שלהלן (בחלק מתרשימי ה‬UML -‫) מאפיין דיסק של שירים ומתואר בתרשים ה‬Disc( ‫הטיפוס דיסק‬
:)‫ שמוצגים בספר יש עמודה נוספת לצורך תיעוד סוגי הפעולות המוגדרות‬UML
'‫כל הזכויות שמורות ל'מבט לחלונות‬
©
22
‫עיצוב תוכנה – טיפוס מורכב‬
public Disc(String n, Song[] s)
public Disc()
public String getName()
public Song[] getSongs()
public void setName(String name)
public void setSongs(Song[] songs)
public void setSong(int index, Song newSong)
public Song getSong(int index)
public void setSong(int index, Song newSong)
public int discLength()
public double averageSongLength()
public int maxSongLength()
public String nameOfLongestSong()
public int numberOfSongsInCategory(String c)
public void displayDiscDetails()
import java.util.*;
class Disc
{
public static Scanner reader = new
Scanner(System.in);
// ‫תכונות‬
private String name;
// Disc name
private Song[] songs;
// Disc songs
// ‫פעולות בונות‬
/** ‫פעולה בונה המקבלת את שם הדיסק ואת מערך‬
‫* השירים שלו‬/
public Disc(String name, Song[] songs)
{
this.name = name;
this.songs = songs;
}
/** ‫פעולה בונה המאתחלת את הדיסק בערכי ברירת‬
‫* המחדל של טיפוסי התכונות‬/
public Disc()
{
}
// ‫פעולות מאחזרות‬
‫קובעות‬
‫חישוביות‬
‫פעולות‬
// ‫פעולות קובעות‬
/** ‫* פעולה הקובעת את שם הדיסק‬/
public void setName(String name)
{
this.name = name;
}
/** ‫* פעולה הקובעת את השירים בדיסק‬/
public void setSongs(Song[] songs)
{
this.songs = songs;
}public Song getSong(int index)
{
return songs[index-1];
}
/** index ‫פעולה הקובעת שיר חדש לשיר שמספרו בדיסק‬
‫* הוא‬/
public void setSong(int index, Song song)
{
songs[index-1] = song;
}
/** ‫* הפעולה מחזירה את אורך הדיסק‬/
public String getName()
{
return name;
}
/** ‫* פעולה המחזירה את השירים בדיסק‬/
public Song[] getSongs()
{
return songs;
}
'‫כל הזכויות שמורות ל'מבט לחלונות‬
‫מאחזרות‬
public int discLength()
{
int sum = 0;
for ( int i=0 ; i<songs.length ; i++ )
{
sum = sum + songs[i].getLength();
}
return sum;
}
/** ‫* פעולה המחזירה את שם הדיסק‬/
23
‫בונות‬
©
‫עיצוב תוכנה – טיפוס מורכב‬
‫הפעולה מחזירה את מספר ‪/** short / long / average‬‬
‫‪ */‬השירים לפי קטגוריה‪:‬‬
‫‪public int numberOfSongsInCategory(String‬‬
‫)‪c‬‬
‫{‬
‫;‪int count = 0‬‬
‫) ‪for ( int i = 0 ; i<songs.length ; i++‬‬
‫{‬
‫))‪if (songs[i].category().equals(c‬‬
‫;‪count++‬‬
‫}‬
‫;‪return count‬‬
‫}‬
‫‪ */‬הפעולה מדפיסה את פרטי הדיסק **‪/‬‬
‫)(‪public void displayDiscDetails‬‬
‫{‬
‫‪System.out.println("The disc name is: " +‬‬
‫;)‪name‬‬
‫) ‪for ( int i = 0 ; i < songs.length ; i++‬‬
‫{‬
‫)‪System.out.println ("Song number " + (i+1‬‬
‫;)" ‪+ " :‬‬
‫;)(‪songs[i].displaySongDetails‬‬
‫}‬
‫}‬
‫}‬
‫‬‫הסבר‬
‫הפתרון‬
‫‬‫‪-‬‬
‫‪-‬‬
‫‪-‬‬
‫‪ */‬הפעולה מחזירה את האורך הממוצע של שיר בדיסק **‪/‬‬
‫)(‪public double averageSongLength‬‬
‫{‬
‫;‪int sum = 0‬‬
‫) ‪for ( int i = 0; i < songs.length; i++‬‬
‫{‬
‫;)(‪sum = sum + songs[i].getLength‬‬
‫}‬
‫;‪return (double)sum/songs.length‬‬
‫}‬
‫‪ */‬הפעולה מחזירה את אורך השיר הארוך בדיסק **‪/‬‬
‫)(‪public int maxSongLength‬‬
‫{‬
‫;)(‪int max = songs[0].getLength‬‬
‫) ‪for ( int i=1 ; i<songs.length ; i++‬‬
‫{‬
‫) ‪if ( songs[i].getLength() > max‬‬
‫;)(‪max = songs[i].getLength‬‬
‫}‬
‫;‪return max‬‬
‫}‬
‫‪ */‬הפעולה מחזירה את שם השיר הארוך בדיסק **‪/‬‬
‫)(‪public String nameOfLongestSong‬‬
‫{‬
‫;‪int n = 0‬‬
‫) ‪for ( int i = 1 ; i < songs.length ; i++‬‬
‫{‬
‫)(‪if(songs[i].getLength()>songs[n].getLength‬‬
‫;‪n = i‬‬
‫}‬
‫;)(‪return songs[n].getName‬‬
‫}‬
‫התכונה מערך שירים היא תכונה ככל התכונות האחרות‪ ,‬ולכן גם עבורה מוגדרות פעולה קובעת‬
‫‪ setSongs‬המקבלת מערך שירים ומאתחלת את התכונה‪ ,‬ופעולה מאחזרת ‪ getSongs‬המחזירה‬
‫את התכונה שהיא מערך השירים‪.‬‬
‫‪ Disc‬ולכן אין צורך שיקבלו‬
‫הפעולות המוגדרות בטיפוס הן פעולות שיופעלו על עצם מטיפוס‬
‫כפרמטר את הדיסק או איזו שהיא תכונה שלו‪.‬‬
‫)‪,numberOfSongsInCategory(String c‬‬
‫הפעולה המחזירה את מספר השירים לפי קטגוריה‬
‫מקבלת כפרמטר מחרוזת ובה הקטגוריה הנדרשת – קטגוריה זו אינה תכונה של הדיסק או של‬
‫אחד משיריו‪ ,‬לכן היא מתקבלת כפרמטר‪.‬‬
‫בכל הפעולות החישוביות יש התייחסות אל התכונה ‪ songs‬שהיא מערך של שירים‪ .‬כאשר יש פניה‬
‫אל ]‪ ,songs[i‬יש פניה אל עצם מטיפוס ‪ Song‬ועליו ניתן להפעיל פעולות המוגדרות בטיפוס ‪.Song‬‬
‫למשל‪.getLength() :‬‬
‫מתוך גוף הפעולה המחזירה את מספר השירים לפי קטגוריה‪ ,‬נסביר את ההוראה‪:‬‬
‫))‪if (songs[i].category().equals(c‬‬
‫;‪count++‬‬
‫‪24‬‬
‫עיצוב תוכנה – טיפוס מורכב‬
‫©‬
‫כל הזכויות שמורות ל'מבט לחלונות'‬
‫ פעולה זו מוגדרת‬.category() ‫ מופעלת הפעולה‬,songs ‫ במערך השירים‬i ‫על השיר הנמצא במקום‬
‫ כדי להשוות את המחרוזת המוחזרת‬.‫ ומחזירה מחרוזת ובה הקטגוריה של השיר‬Song ‫בטיפוס‬
‫ המופעלת על עצם מטיפוס מחרוזת שהוא‬equals
‫ יש שימוש בפעולה‬,‫למחרוזת בפרמטר‬
‫ הפעולה מקבלת כפרמטר‬,String ‫ בטיפוס‬equals ‫ בהתאם להגדרת הפעולה‬.songs[i].category()
.c ‫מחרוזת להשוואה במקרה זה המחרוזת‬
‫מימוש המחלקה הראשית‬
:‫ מממשת את האלגוריתם הבא‬TestDisc ‫הפעולה הראשית במחלקה הראשית‬
.d ‫ והשם אותו במשתנה‬Disk ‫) בנה עצם חדש מטיפוס‬1
‫ והשם את התוצאה במשתנה‬discLength() ‫ ע"י הפעולה‬d ‫) חשב את האורך הכולל של הדיסק‬2
.totalLength ‫השלם‬
.totalLength ‫) הדפס את אורך הדיסק מתוך המשתנה‬3
.averageSongLength() ‫ ע"י הפעולה‬d ‫) חשב והדפס את הממוצע של אורך שיר בדיסק‬4
.nameOfLongestSong() ‫ ע"י הפעולה‬d ‫) חשב והדפס את שם השיר הארוך ביותר בדיסק‬5
.numberOfSongsInCategory("short") ‫) חשב והדפס את מספר השירים ה"קצרים" ע"י הפעולה‬6
class TestDisc
{
// ‫הפעולה הראשית‬
public static void main(String[] args)
{
String songName, performer;
int length;
System.out.println("Enter disc name : ");
String name = reader.next();
System.out.println("Enter number of songs on disc: ");
Song[] songs = new Song[reader.nextInt()];
for ( int i=0 ; i<songs.length ; i++ )
{
System.out.println("Enter song no. "+i+" name : ");
songName = reader.next();
System.out.println("Enter song no. "+i+" performer : ");
performer = reader.next();
System.out.println("Enter song no. "+i+" length : ");
length = reader.nextInt();
songs[i] = new Song(songName, performer,length);
}
Disc d = new Disc(name, songs);
int totalLength = d.discLength();
System.out.println("The disc total length is : " + totalLength );
System.out.println ("The average song length is: " + d.averageSongLength());
System.out.println ("The longest song is: " + d.nameOfLongestSong());
System.out.println ("The number of short songs is: " +
d.numberOfSongsInCategory("short"));
}
25
'‫כל הזכויות שמורות ל'מבט לחלונות‬
©
‫עיצוב תוכנה – טיפוס מורכב‬
‫הסבר‬
‫הפתרון‬
‫}‬
‫הסבר גוף הפעולה הראשית‪ :‬בפעולה הראשית נבנה עצם מן הטיפוס המורכב ‪ Disc‬באותו אופן‬
‫בו נבנו עצמים מטיפוס פשוט כדוגמת ‪ .Song‬על העצם ‪ d‬שהוא מטיפוס ‪ Disc‬אפשר להפעיל את‬
‫הפעולות המוגדרות בטיפוס שלו‪.‬‬
‫הפעולה ‪ toString‬על עצמים‬
‫חושבים‬
‫במחלקה ‪ Disc‬הוגדרה הפעולה )(‪ displayDiscDetails‬המדפיסה את כל התכונות של הדיסק‪.‬‬
‫הפעלה שלה בתכנית הראשית תהיה למשל‪:‬‬
‫רגע‪..‬‬
‫;)" ‪System.out.println ("The disc details:‬‬
‫;)(‪d.displayDiscDetails‬‬
‫;) ‪System.out.println (d‬‬
‫האם ניתן פשוט להדפיס את פרטי הדיסק כך?‪:‬‬
‫הסבר‬
‫הפתרון‬
‫הדפסה כזו תביא להפעלה אוטומטית של הפעולה ‪ toString‬על הדיסק ‪ .d‬כאשר פעולה זו מופעלת על‬
‫עצם‪ ,‬הפעולה ‪ toString‬תחזיר למשל את המחרוזת הבאה‪Disc@162e295 :‬‬
‫במחרוזת זו מופיע תחילה שם המחלקה לאחריו התו @ ואחר כך ההפנייה של העצם שהודפס‪.‬‬
‫מחרוזת זו אינה המחרוזת בה אנו מעוניינים הכוללת את כל ערכי התכונות של הדיסק‪ .‬אם אנו‬
‫מעוניינים בהדפסה "אוטומטית" כזו עלינו להגדיר מחדש את הפעולה ‪ toString‬עבור המחלקה שלנו‪.‬‬
‫ההבדל יהיה בכך שכל הפרטים הנדרשים להופיע בפלט ישורשרו למחרוזת אחת שתוחזר ע"י הפעולה‬
‫‪ toString‬ואז הוראת הפלט שהוצגה לעיל אמנם תתן את הרצוי‪ .‬כלומר בכל פעם שנבקש להדפיס‬
‫עצם מטיפוס ‪ Disc‬תופעל עליו הפעולה ‪ toString‬המחזירה מחרוזת המתארת אותו והיא זו שתודפס‪.‬‬
‫נגדיר את הפעולה באופן זה‪:‬‬
‫‪ */‬הפעולה מחזירה מחרוזת המכילה את פרטי הדיסק **‪/‬‬
‫)(‪public String toString‬‬
‫{‬
‫;"‪String discDetails = "The disc details:"+"\n"+"The disc name is: "+name +"\n‬‬
‫) ‪for ( int i = 0 ; i < songs.length ; i++‬‬
‫{‬
‫;"‪discDetails = discDetails + "Song number " + (i+1) + " : " + songs[i] + "\n‬‬
‫}‬
‫;‪return discDetails‬‬
‫}‬
‫המחרוזת המוחזרת מאותחל תחילה להיות המחרוזת " ‪ ."The disc details:‬תת המחרוזת "‪"/n‬‬
‫מסמנת ירידה בשורה תוך כדי ההדפסה ולאחריה המחרוזת " ‪ "The disc name is:‬משורשרת לשם‬
‫הדיסק ושוב ירידה של שורה בהדפסה‪ .‬לאחר מכן משורשרים פרטי כל השירים בדיסק‪ ,‬אחרי כל שיר‬
‫יש ירידה בשורה‪ .‬המחרוזת הכוללת בה כלולים כל פרטי הדיסק יחד עם הנחיות הדפסה מוחזרת‪.‬‬
‫שים ‪ :‬כדי שפעולה זו תפעל כראוי יש צורך בהתאמה להגדיר פעולה ‪ toString‬במחלקה ‪.Song‬‬
‫‪26‬‬
‫עיצוב תוכנה – טיפוס מורכב‬
‫©‬
‫כל הזכויות שמורות ל'מבט לחלונות'‬
‫כתוב מחלקה‬
‫תרגילים לטיפוס מורכב‪... :‬‬
‫‪‬‬
‫תרגיל ‪ :7‬הגדרת פעולות )(‪ toString‬במחלקות ‪ Song‬ו‪Disc -‬‬
‫הגדר במחלקות ‪ Song‬ו‪ Disc -‬את הפעולות )(‪ toString‬ובדוק אותן ע"י הדפסה ישירה של עצמים‬
‫מטיפוסים אלו בתכנית הראשית‪.‬‬
‫תרגיל ‪ :8‬הגדרת פעולה בטיפוס כיתה – המחזירה מערך תלמידים ‪‬‬
‫בטיפוס כיתה הוגדרה הפעולה )(‪ bestInClass‬אשר מחזירה את התלמיד המצטיין בכיתה‪ .‬התלמיד‬
‫המצטיין הוא התלמיד שהממוצע שלו הגבוה ביותר‪ .‬מה קורה אם יש מספר תלמידים בעלי אותו‬
‫ממוצע? בפעולה שהוגדרה בגוף הפרק יוחזר התלמיד הראשון שימצא‪ .‬איננו רוצים להסתפק בהגדרת‬
‫פעולה זו מאחר ואינה מתאימה למציאות‪ .‬כדי שנוכל להתאים פעולה זו למצב בו יש יותר ממצטיין‬
‫אחד‪ ,‬על הפעולה להחזיר מערך של תלמידים מצטיינים‪ .‬כלומר מערך שיהיו בו כל התלמידים שיש‬
‫להם את הממוצע הגבוה ביותר‪ .‬כתוב פעולה )(‪ bestsInClass‬המחזירה מערך ובו התלמידים בעלי‬
‫הממוצע הגבוה ביותר‪ .‬שים ‪ :‬מה יהיה גודל המערך המוחזר? איך נדע כמה תלמידים יש בו?‬
‫תרגיל ‪ :9‬הגדרת פעולה בטיפוס דיסק – מספר השירים בכל קטגוריה ‪‬‬
‫הגדר בטיפוס ‪ Disc‬פעולה המחזירה מערך מונים בן ‪ 3‬תאים‪ .‬בתא הראשון יהיה מספר השירים‬
‫הקצרים בדיסק‪ ,‬בתא השני יהיה מספר השירים הממוצעים בדיסק‪ ,‬בתא השלישי יהיה מספר‬
‫‪ TestDisc‬לבדיקת‬
‫השירים הארוכים בדיסק‪ .‬הוסף הוראה מתאימה בפעולה הראשית במחלקה‬
‫הפעולה‪.‬‬
‫תרגיל ‪ :10‬שינוי פעולות בטיפוס דיסק – החזרת השיר הארוך ‪‬‬
‫בטיפוס ‪ Disc‬הוגדרו שתי פעולות המבצעות מבחינה אלגוריתמית את אותה המשימה‪ .‬הפעולה‬
‫)(‪nameOfLongestSong‬‬
‫)(‪ maxSongLength‬מחזירה את אורך השיר הארוך ביותר‪ .‬הפעולה‬
‫מחזירה את שם השיר הארוך ביותר‪ .‬במקום שתי הפעולות האלה הגדר פעולה )(‪theLongestSong‬‬
‫המחזירה את השיר שאורכו הוא הארוך ביותר בדיסק‪.‬‬
‫הוסף את ההוראות הבאות בפעולה הראשית במחלקה ‪:TestDisc‬‬
‫‪ )1‬מצא את השיר הארוך ביותר בדיסק על ידי הפעולה )(‪ theLongestSong‬והשם את השיר ב‪-‬‬
‫‪.maxSong‬‬
‫‪ )2‬הדפס את שם השיר ‪ maxSong‬ואת אורכו‪.‬‬
‫בפרק זה הודגם שימוש במערך של עצמים שהוא תכונה של עצם מטיפוס מורכב (למשל‪ ,‬מערך שירים‬
‫בטיפוס דיסק)‪ .‬בעבר (בספר יסודות מדעי המחשב‪ ,‬חלק ב‪ ,‬פרק ‪ )7‬הודגם שימוש במערך של עצמים‬
‫ששימש כמשתנה בתכנית הראשית‪.‬‬
‫נשאלת השאלה‪ :‬האם יש הבדל בדרך בה אנו משתמשים במערך בשני ההקשרים?‬
‫עיצוב תוכנה – טיפוס מורכב‬
‫©‬
‫כל הזכויות שמורות ל'מבט לחלונות'‬
‫‪27‬‬
‫התשובה היא‪ :‬לא‪.‬‬
‫הטיפול במערך של עצמים הוא זהה בכל מקרה‪ .‬לא חשוב אם מערך העצמים הוא משתנה מקומי‬
‫(בפעולה הראשית או בכל פעולה אחרת) או תכונה של עצם‪.‬‬
‫למרות עקרון זה יש הבדלים הניכרים במרכיבים הבאים‪:‬‬
‫(‪ )1‬בדרך הפנייה אל משתנה או אל תכונה‪.‬‬
‫(‪ )2‬בדרך הגדרת הפעולות – האם הן פעולות סטטיות במחלקה ראשית אשר מקבלות את המערך‬
‫כפרמטר‪ ,‬או שהן פעולות המוגדרות בטיפוס המייצג ישות‪ ,‬ואז הן לא תהיינה סטטיות‪ ,‬וגם לא‬
‫תקבלנה את המערך כפרמטר‪ .‬פעולות אלו תופעלנה על עצם שהמערך הוא אחת התכונות שלו ולכן‬
‫אין צורך בפרמטר‪.‬‬
‫דוגמה לשימוש במערך עצמים כמשתנה או כתכונה‬
‫חלק מן הפעולות שהוגדרו בטיפוס דיסק בפרק זה הוגדרו בספר יסודות חלק ב בפרק ‪ :7‬מערך של‬
‫עצמים‪ ,‬דוגמה ‪ .2‬התייחסו ת למשתנה שהוא מערך של עצמים אשר הוגדר למשל בתכנית הראשית‬
‫‪ .Disc‬האלגוריתמים‬
‫‪ ,SongProgram2‬זהה לטיפול במערך של עצמים שהוא תכונה בטיפוס‬
‫המתייחסים למערך השירים הם אותם אלגוריתמים אך יש הבדלים בדרך הגישה אל מערך השירים‪.‬‬
‫נסתכל ונשווה למשל את הפעולה המחשבת את ממוצע אורכי השירים הנמצאים במערך שירים‬
‫במחלקה ‪ ,SongProgram2‬אל הפעולה המחשבת את ממוצע אורכי השירים של השירים בדיסק‬
‫במחלקה ‪ .Disc‬ברור כי האלגוריתם לביצוע הפעולה הוא זהה‪ .‬בכל מקרה לצורך חישוב הערך‬
‫המוחזר‪ ,‬יש לצבור את אורכי השירים ולחלק במספר השירים‪ .‬ההבדלים באים לידי ביטוי בכותרת‬
‫הפעולה‪ ,‬בשם המערך המיוחס בגוף הפעולה‪ ,‬ובדרך זימון הפעולה‪.‬‬
‫פעולה סטטית שהוגדרה במחלקה ראשית‬
‫פעולה פנימית שהוגדרה במחלקה ‪Disc‬‬
‫כותרת הפעולה‪:‬‬
‫‪public static double averageSongLength‬‬
‫][‪(Song‬‬
‫)‪s‬‬
‫ הפעולה היא סטטית כי לא תופעל על עצם‪.‬‬‫ הפעולה מקבלת את מערך השירים כפרמטר כדי‬‫שתוכל להתייחס אל ערכיו‪.‬‬
‫גוף הפעולה‪:‬‬
‫;‪int sum = 0‬‬
‫)‪for ( int i = 0 ; i<s.length ; i++‬‬
‫{‬
‫;)(‪sum = sum + s[i] . getLength‬‬
‫}‬
‫;‪return (double)sum/s.length‬‬
‫}‬
‫כותרת הפעולה‪:‬‬
‫()‪public double averageSongLength‬‬
‫ הפעולה אינה סטטית כי היא תופעל על עצם‪.‬‬‫ הפעולה לא מקבלת את מערך השירים כפרמטר כי מערך‬‫השירים הוא תכונה של העצם עליו תופעל הפעולה‪.‬‬
‫גוף הפעולה‪:‬‬
‫{‬
‫;‪int sum = 0‬‬
‫) ‪for ( int i = 0 ; i<songs.length ; i++‬‬
‫{‬
‫;)(‪sum = sum + songs[i] . getLength‬‬
‫}‬
‫;‪return (double)sum/songs.length‬‬
‫}‬
‫}‬
‫ האלגוריתם בגוף הפעולה זהה‪.‬‬‫ הפעולה מתייחסת אל המערך שהתקבל כפרמטר‬‫‪.s‬‬
‫ האלגוריתם בגוף הפעולה זהה‪.‬‬‫ הפעולה מתייחסת אל המערך שהוא התכונה של העצם עליו‬‫הופעלה‪ ,‬על פי שם התכונה ‪.songs‬‬
‫‪28‬‬
‫עיצוב תוכנה – טיפוס מורכב‬
‫©‬
‫כל הזכויות שמורות ל'מבט לחלונות'‬
‫זימון הפעולה‪:‬‬
‫)‪public static void main(String[] args‬‬
‫{‬
‫;)(‪Song[] songs = initialSongArray‬‬
‫‪System.out.println("The average song‬‬
‫‪length is:‬‬
‫;))‪"+averageSongLength(songs‬‬
‫}‬
‫ הפעולה הראשית מוגדרת במחלקה‬‫‪.SongProgram2‬‬
‫ הפעולה הראשית מוגדרת באותה מחלקה בה‬‫מוגדרת הפעולה ‪.averageSongLength‬‬
‫ שם מערך השירים שהוא משתנה של הפעולה‬‫הראשית הוא ‪.songs‬‬
‫ מערך השירים מאותחל על ידי שירים בעזרת‬‫הפעולה )(‪ initialSongArray‬שאף היא פעולה‬
‫סטטית במחלקה ‪.SongProgram2‬‬
‫ המערך ‪ songs‬מועבר כפרמטר לפעולה‬‫‪ averageSongLength‬כדי לחשב את ממוצע‬
‫אורכי השירים הנמצאים בו‪.‬‬
‫זימון הפעולה‪:‬‬
‫)‪public static void main(String[] args‬‬
‫{‬
‫;‪String songName, performer‬‬
‫;‪int length‬‬
‫;)" ‪System.out.println("Enter disc name :‬‬
‫;)(‪String name = reader.next‬‬
‫;)"‪System.out.println("Enter songs no.‬‬
‫;])(‪songs = new Song[reader.nextInt‬‬
‫) ‪for ( int i=0 ; i<songs.length ; i++‬‬
‫{‬
‫;)" ‪System.out.println("Enter song name:‬‬
‫;)(‪SongName = reader.next‬‬
‫;)" ‪System.out.println("Enter song performer:‬‬
‫;)(‪performer = reader.next‬‬
‫;)" ‪System.out.println("Enter song length:‬‬
‫;)(‪length = reader.nextInt‬‬
‫‪songs[i] = new Song(songName,‬‬
‫;)‪performer,length‬‬
‫}‬
‫;)‪Disc d = new Disc(name, d‬‬
‫‪System.out.println ("The average song‬‬
‫;))(‪length is: "+ d.averageSongLength‬‬
‫}‬
‫ הפעולה הראשית מוגדרת במחלקה ‪ .TestDisc‬בעוד‬‫הפעולה ‪ averageSongLength‬מוגדרת בתוך הטיפוס‬
‫‪.Disc‬‬
‫ מערך השירים הוא תכונה של הדיסק ‪ ,d‬ולכן אינו מופיע‬‫במפורש בגוף הפעולה הראשית‪.‬‬
‫ מערך השירים מאותחל על ידי שירים בעזרת הפעולה הבונה‬‫של דיסק‪. Disc(name,d) :‬‬
‫ אין צורך להעביר אף פרמטר לפעולה‬‫‪ averageSongLength‬כדי לחשב את ממוצע אורכי‬
‫השירים בדיסק ‪ .d‬הפעולה מופעלת על הדיסק עצמו‪ ,‬ומערך‬
‫השירים הוא תכונה שלו‪.‬‬
‫עד כה התייחסנו אל תכונות המאפיינות עצמים‪ .‬לפעמים יש צורך בתכונה המשותפת לכל העצמים‬
‫במחלקה‪ .‬תכונה של מחלקה היא תכונה המוגדרת כ ‪ static‬ושעבורה מוקצה זיכרון רק פעם אחת ואין‬
‫הקצאת זיכרון נפרדת עבור כל עצם שנוצר כמו לגבי התכונות שהכרנו עד כה‪ .‬הערך שלה ברגע מסוים‬
‫זהה לגבי כל העצמים‪ .‬לתכונה זו ניתן לפנות דרך העצמים או דרך המחלקה‪ .‬כל שינוי בתכונה גם אם‬
‫נעשה על ידי עצם אחד של המחלקה חל למעשה לגבי כולם – כי יש לו שטח זיכרון אחד‪.‬‬
‫עיצוב תוכנה – טיפוס מורכב‬
‫©‬
‫כל הזכויות שמורות ל'מבט לחלונות'‬
‫‪29‬‬
‫דוגמה‪ :‬שיוך מספר סידורי לכל עצם שנוצר מן המחלקה‬
‫נניח שאנו מפתחים מבחן ממוחשב‪ .‬כל נבחן מקליד את שמו ומקבל מספר נבחן שהוא מספר סידורי‬
‫עוקב ביחס לכל הנבחנים‪ .‬נסתפק בהגדרת התכונות הבאה עבור כל תלמיד‪ :‬שם‪ ,‬מספר נבחן והמבחן‬
‫עצמו‪ .‬כדי שכל נבחן יקבל מספר אחר ייחוד י לו וגם עוקב לנבחן הקודם‪ ,‬יש להגדיר תכונה משותפת‬
‫תלמיד‪-‬נבחן תקדם את מונה הנבחנים‬
‫לכל הנבחנים‪ ,‬כתכונה סטטית‪ .‬כל בניה של עצם מטיפוס‬
‫מספר‪-‬נבחן של התלמיד‪ .‬להלן חלקים מקוד המחלקות‬
‫הכללי ותציב את ערך המונה לתכונה‬
‫בפרויקט ותוצאות הרצה של הפעולה הראשית‪.‬‬
‫‪public class TestStudent‬‬
‫{‬
‫‪ – testCounter‬תכונה של מחלקה‬
‫;‪private static int testCounter = 0‬‬
‫ומוגדרת כ‪static -‬‬
‫;‪private String name‬‬
‫;‪private int num‬‬
‫;‪private Test t‬‬
‫בהנחה שקיים טיפוס עבור הבחינה ‪//‬‬
‫)‪TestStudent(String name‬‬
‫{‬
‫;‪this.name = name‬‬
‫קידום התכונה של המחלקה ‪testCounter‬‬
‫;‪testCounter ++‬‬
‫;‪this.num = testCounter‬‬
‫והשמת ערכה לתכונה ‪ num‬המיוחסת לעצם‬
‫}‬
‫שנבנה‬
‫)( ‪public static int getTestCounter‬‬
‫פעולה מאחזרת לתכונה חייבת להיות ‪static‬‬
‫{‬
‫;‪return testCounter‬‬
‫כי היא מתייחסת לתכונה שהיא ‪static‬‬
‫}‬
‫)(‪public String toString‬‬
‫{‬
‫;‪return "name = " + name + " --- " + num‬‬
‫}‬
‫}‬
‫‪public class MainTest‬‬
‫{‬
‫)(‪public static void main‬‬
‫{‬
‫קבלת ערך התכונה‬
‫;)"‪TestStudent s1 = new TestStudent("aaa‬‬
‫‪ testCounter‬דרך‬
‫;)"‪TestStudent s2 = new TestStudent("bbb‬‬
‫המחלקה או דרך כל‬
‫;)"‪TestStudent s3 = new TestStudent("ccc‬‬
‫עצם של המחלקה‬
‫;)‪System.out.println(s1‬‬
‫;)‪System.out.println(s2‬‬
‫;)‪System.out.println(s3‬‬
‫;))( ‪System.out.println("testCounter value: " + TestStudent.getTestCounter‬‬
‫;))( ‪System.out.println("testCounter value: " + s2.getTestCounter‬‬
‫}‬
‫}‬
‫הפלט המתקבל הוא‪:‬‬
‫‪name = aaa --- 1‬‬
‫‪name = bbb --- 2‬‬
‫‪name = ccc --- 3‬‬
‫‪testCounter value: 3‬‬
‫‪testCounter value: 3‬‬
‫‪30‬‬
‫עיצוב תוכנה – טיפוס מורכב‬
‫©‬
‫כל הזכויות שמורות ל'מבט לחלונות'‬
‫נזכרים‬
‫רגע‪ ..‬בשני מקרים כבר הוצג שימוש בהגדרת משתנים ‪:static‬‬
‫‪ ‬עבור קבועים – כאשר יש צורך רק בערך אחד‪ .‬בעבור קבוע נוספה גם ההגדרה ‪ final‬כי לאחר‬
‫שנקבע עבורו ערך הוא לא משתנה יותר‪.‬‬
‫‪ ‬עבור המשתנה מטיפוס ‪ Scanner‬המשמש לקלט ( ‪ – )reader‬אין צורך ביותר מעצם אחד‬
‫לביצוע קלט‪ .‬הקלט בכל מקרה מושם למשתנה הנדרש‪.‬‬
‫כאשר ניגשים לפתרון בעיה בתכנות מונחה עצמים יש לזהות תחילה את העצמים השותפים לפתרון‬
‫הבעיה‪ .‬העצמים הם הגורם המרכזי – בעזרתם מתבצעות פעולות – ולכן קוראים לסגנון תכנות זה‬
‫תכנות מונחה עצמים‪ .‬בדרך כלל בפתרון בעיה יש שימוש במספר עצמים בעלי אותם מאפיינים ולכן‬
‫מגדירים טיפוס‪ .‬טיפוס משמש תבנית ליצירת עצמים שלכל אחד מהם יש את אותן התכונות‪ ,‬ועל כל‬
‫אחד מהם ניתן להפעיל את אותן הפעולות‪ .‬אחרי אפיון הטיפוסים ניתן לפתח כל טיפוס כמחלקה‬
‫בשפת התכנות‪ .‬הפיתוח הוא מודולארי ומתייחס רק לממשק הטיפוסים האחרים‪ .‬כאשר טיפוס אחד‬
‫משתמש בטיפוס אחר‪ ,‬הדבר יכול לבוא לידי ביטוי בטיפוס של‪ :‬תכונות‪ ,‬פרמטרים‪ ,‬משתנים‬
‫מקומיים‪ ,‬או ערכים מוחזרים‪ .‬אין צורך בפעולה מיוחדת כדי להגיד שטיפוס אחד משתמש בטיפוס‬
‫אחר ומספיק שהוא מופיע באחד ההקשרים שפורטו‪ .‬על כל עצם מטיפוס‪ ,‬המופיע בטיפוס אחר ניתן‬
‫להפעיל את כל הפעולות המוגדרות בטיפוס שלו‪ .‬האלגוריתם הראשי לפתרון הבעיה ייכת ב במחלקה‬
‫ראשית‪ ,‬מחלקה שאינה מייצגת עצמים‪ ,‬אלא מנהלת את האלגוריתם לפתרון הבעיה הרצויה‪.‬‬
‫להלן מתכון לפתרון בעיה בתכנות מונחה עצמים‪:‬‬
‫(‪ )1‬זיהוי העצמים הנדרשים לפתרון הבעיה‪.‬‬
‫(‪ )2‬אפיון הטיפוסים של העצמים (טיפוסים המייצגים ישויות)‪.‬‬
‫(‪ )3‬פיתוח כל טיפוס בנפרד כמחלקה בשפת התכנות (תכונות‪ ,‬פעולות)‪.‬‬
‫(‪ )4‬פיתוח המחלקה הראשית ובה הפעולה הראשית שבה מופיע האלגוריתם הראשי לפתרון הבעיה‪.‬‬
‫כאשר בעיה מוצגת באופן מילולי בעברית‪ ,‬דרך אפשרית היא לנתח אותה מבחינה לשונית‬
‫במטרה לזהות את הישויות ואת הפעולות הנדרשות עבורם‪ .‬הזיהוי הלשוני הוא לפי הכללים‬
‫הבאים‪ :‬שמות עצם עשויים לציין עצמים (שיוכללו לטיפוסים) ופעלים עשויים לציין פעולות‪.‬‬
‫כתוב מחלקה‬
‫תרגילים לטיפוס מורכב‪ :‬כתוב מחלקה‪...‬‬
‫שים ‪ :‬בכל מקרה בו יש לפתח מחלקה‪ ,‬הבסיס לפיתוח כולל‪ :‬הגדרת תכונות‪ ,‬הגדרת פעולות‬
‫בונות‪ ,‬והגדרת פעולות מאחזרות וקובעות לכל תכונה‪.‬‬
‫תרגיל ‪ 11‬רכבות ‪‬‬
‫הטיפוס קטר )‪ (Engine‬מאופיין על‪-‬ידי מספר רישוי ושנת יצור‪.‬‬
‫הטיפוס קרון‪-‬רכבת )‪ (Carriage‬מאופיין על‪-‬ידי מספר סידורי של הקרון‪ ,‬ומספר הנוסעים שיכולים‬
‫לנסוע בו‪ .‬הטיפוס רכבת )‪ (Train‬מאופיין על‪-‬ידי קטר ומערך של ‪ n‬קרונות‪ ,‬מספר הקרונות שיש‬
‫ברכבת בפועל ( ‪ n‬הוא מספר הקרונות המקסימלי שהרכבת יכולה להכיל)‬
‫עיצוב תוכנה – טיפוס מורכב‬
‫©‬
‫כל הזכויות שמורות ל'מבט לחלונות'‬
‫‪31‬‬
‫א‪ .‬פתח מחלקה לכל אחד מהטיפוסים‪.‬‬
‫ב‪ .‬ממש את הפעולות החישוביות הבאות במחלקה רכבת‪:‬‬
‫‪ .1‬החלף את הקטר של הרכבת‪( .‬האם פעולה זו כבר הוגדרה לפני כן?)‬
‫‪ .2‬הוסף קרון לרכבת‪.‬‬
‫‪ .3‬החזר את מספר הנוסעים הכולל ברכבת‪.‬‬
‫‪ .4‬החזר את מספר הנוסעים הממוצע לקרון ברכבת‪.‬‬
‫ג‪ .‬פתח מחלקה ראשית הבונה רכבת‪ ,‬מפעילה את הפעולות שמימשת בסעיף ב ומציגה את נתוני הרכבת‪.‬‬
‫תרגיל ‪ :12‬הטיפוס משחק רובוטים ‪‬‬
‫פתח מחלקה משחק‪-‬רובוטים ‪ RobotGame‬שבה שתי תכונות‪ :‬מספר המשבצות בלוח המשחק ומערך‬
‫הרובוטים המשתתפים במשחק‪ .‬המחלקה תשתמש במחלקה ‪ Robot‬ותוגדרנה בה פעולות מתאימות‬
‫לניהול משחק הרובוטים כפי שתואר בספר יסודות‪ ,‬חלק ב בעמוד ‪ .146‬הרובוטים יכולים לנוע קדימה‬
‫או אחורה‪ .‬רובוט אשר חורג בצעדיו מגבולות לוח המשחק יוצא מן המשחק‪.‬‬
‫המאפיינים הבסיסיים של כל רובוט הם‪:‬‬
‫תכונות‪ :‬צבע‪ ,‬מספר משבצת עליו הוא עומד‪ ,‬האם נמצא במשחק?‪.‬‬
‫פעולות חישוביות‪ :‬צעד קדימה ‪ -‬הרובוט נע משבצת אחת קדימה‪ ,‬צעד אחורה ‪ -‬הרובוט נע‬
‫משבצת אחת לאחור‪ ,‬קפוץ קדימה ב‪ n -‬צעדים‪ ,‬קפוץ אחורה ב‪ n -‬צעדים‪.‬‬
‫על הפעולה הראשית לנהל בין הרובוטים משחק אקראי‪ .‬כללי המשחק הם‪ :‬הרובוטים מתחילים‬
‫‪ 4‬אפשרויות)‪ .‬אם‬
‫במשבצת מספר ‪ .10‬בכל שלב עבור כל רובוט מוגרלת פעולת ההתקדמות שלו (‬
‫הוגרלה פעולת קפיצה יש להגריל גם את ערך הקפיצה מ ‪ .1-6‬הרובוט הראשון שנעמד על המשבצת‬
‫‪ 100‬הוא המנצח‪ .‬אם רובוט מגיע למשבצת עליה נמצא רובוט אחר הוא מוציא את הרובוט השני מן‬
‫המשחק‪.‬‬
‫הגדר פעולה נוספת המחזירה את הרובוט הנמצא על משבצת שמספרה הוא הגדול ביותר‪ .‬פתח‬
‫מחלקה ראשית בה יוגדר עצם מטיפוס משחק‪-‬רובוטים‪ ,‬ותזומן הפעולה לניהול המשחק‪.‬‬
‫תרגיל ‪ :13‬הטיפוס מרוץ מכוניות ‪‬‬
‫פתח מחלקה מרוץ‪-‬מכוניות ‪ CarRace‬שבה שתי תכונות‪ :‬מספר המכוניות המשתתפות במרוץ ומערך‬
‫המכוניות המשתתפות במרוץ‪ .‬המחלקה תשתמש במחלקה ‪( Car‬אפשר להוריד את המחלקה מאתר‬
‫האינטרנט באתר מלווה ספר בגאווה)‪ .‬ותוגדרנה בה פעולות מתאימות לניהול המרוץ כפי שתואר‬
‫בספר יסודות‪ ,‬חלק ב‪ ,‬תרגיל ‪ 3‬בעמוד ‪ :157‬עם פתיחת המרוץ כל המכוניות מזנקות בו זמנית‪ .‬במהלך‬
‫המרוץ המכונית מאטה או מאיצה לחלופין‪ .‬מדמה המרוץ שלנו יגריל עבור כל מכונית בכל שלב מספר‬
‫שלם בתחום של ‪ .1-4‬קוד ‪ – 1‬המכונית מגבירה מהירותה ב‪ 10 -‬קמ"ש (בתנאי שלא עברה את‬
‫המהירות המקסימלית שלה) ‪ ,‬קוד ‪ – 2‬המכונית מאטה את מהירותה ב‪ 10 -‬קמ"ש (בתנאי שלא ירדה‬
‫ממהירות ‪ 0‬קמ"ש)‪ ,‬קוד ‪ – 3‬המכונית מאטה את מהירותה ב‪ 20 -‬קמ"ש (בתנאי שלא ירדה ממהירות‬
‫‪ 0‬קמ"ש)‪ ,‬קוד ‪ – 4‬ארעה תקלה או התנגשות – המכונית פורשת מן המרוץ‪ .‬המכונית שחוצה ראשונה‬
‫את קו הסיום היא המנצחת במרוץ‪.‬‬
‫הגדר פעולה נוספת המחזירה את המכונית המובילה במרוץ‪ .‬פתח מחלקה ראשית בה יוגדר עצם‬
‫מטיפוס מרוץ‪-‬מכוניות‪ ,‬ותזומן הפעולה לניהול המרוץ‪.‬‬
‫הרחבה‪ :‬נניח שברצוננו לעקוב אחר התנהלות כל מכונית המשתתפת במרוץ לאורך המרוץ‪ .‬לצורך כך‬
‫‪32‬‬
‫עיצוב תוכנה – טיפוס מורכב‬
‫©‬
‫כל הזכויות שמורות ל'מבט לחלונות'‬
‫יש לדעת בכל שלב כמה פעמים המכונית שינתה מהירות (האטה או האיצה)‪ .‬תכנן את השינויים‬
‫הנדרשים‪ .‬עבור כל תוספת שתאפשר את פתרון הבעיה המורחבת‪ ,‬שים דגש על זיהוי המחלקה‬
‫המתאימה להגדיר בה את התוספת‪.‬‬
‫‪‬‬
‫תרגיל ‪ :14‬חייל מילואים‬
‫א‪ .‬הגדר מחלקה תאריך )‪ (MyDate‬שמאפייניה הם יום‪ ,‬חודש ושנה‪ ,‬המכילה פעולה בונה לפי‬
‫*‬
‫פרמטרים‪ ,‬פעולות קובעות‪ ,‬פעולות מאחזרות‪ ,‬ואת הפעולות החישוביות הבאות‪:‬‬
‫‪ .1‬פעולה המחזירה מחרוזת המתארת את התאריך ( ‪.(toString‬‬
‫‪ .2‬פעולה המחזירה את היום העוקב ליום עליו מופעלת הפעולה‪.‬‬
‫‪ .3‬פעולה המחזירה את היום הקודם ליום עליו מופעלת הפעולה‪.‬‬
‫‪ .4‬פעולה המקבלת תאריך ומחזירה את ההפרש בימים בין התאריך עליו מופעלת הפעולה ובין‬
‫התאריך שהתקבל כפרמטר‪.‬‬
‫* ניתן להיעזר במחלקה ‪ Date‬הבנויה ב‪http://java.sun.com/j2se/1.5.0/docs/api/index.html Java-‬‬
‫ב‪ .‬הטיפוס חייל מילואים )‪ (Soldier‬מאופיין על‪-‬ידי מספר אישי‪ ,‬דרגה‪ ,‬תאריך לידה‪ ,‬תאריך גיוס‬
‫לשרות סדיר ותאריך שחרור משרות סדיר‪ .‬בנה מחלקה המגדירה את תכונות הטיפוס‪ ,‬פעולה‬
‫בונה‪ ,‬פעולות קובעות‪ ,‬פעולות מאחזרות ואת הפעולה ‪ .toString‬כמו‪-‬כן תכיל המחלקה פעולה‬
‫‪ true‬אם חייל מילואים צריך להשתחרר‬
‫בוליאנית המקבלת את התאריך של היום ומחזירה‬
‫ממילואים או לא‪ .‬חייל מילואים משתחרר כאשר הוא מגיע לגיל ‪.40‬‬
‫ג‪ .‬כתוב מחלקה ראשית הבונה בפעולה הראשית מערך של ‪ N‬חיילי מילואים ומזמנת את הפעולות‬
‫הסטטיות הבאות‪:‬‬
‫‪ )1‬פעולה המדפיסה לכל חייל מילואים את משך תקופת השרות הסדיר שלו בימים‪.‬‬
‫‪ )2‬פעולה המקבלת את התאריך של יום מסוים‪ ,‬מוציאה ממערך החיילים את חיילי המילואים‬
‫שצריכים להשתחרר‪ ,‬ומחזירה את מספר החיילים המעודכן שנשארו במערך‪ .‬יש להקפיד‬
‫שאברי המערך יופיעו במערך ברצף‪.‬‬
‫‪ )3‬פעולה המקבלת את מערך החיילים ואת מספר החיילים במערך ומדפיסה את פרטיהם‪.‬‬
‫תרגיל ‪ :15‬תעודת זהות ‪‬‬
‫תעודת זהות של קטין מאופיינת על‪-‬ידי מספר תעודת‪-‬זהות‪ ,‬שם פרטי‪ ,‬שם משפחה‪ ,‬תאריך לידה‪,‬‬
‫ארץ לידה‪ ,‬ולאום‪ .‬תעודת זהות של מבוגר מאופיינת על‪-‬ידי מספר תעודת‪-‬זהות‪ ,‬שם פרטי‪ ,‬שם‬
‫משפחה‪ ,‬תאריך לידה‪ ,‬ארץ לידה ורשימת תעודות זהות של ילדיו הקטינים – עד ‪.15‬‬
‫א‪ .‬בנה מחלקות לייצוג הטיפוסים הדרושים‪ .‬חשוב‪ ,‬האם ניתן להשתמש באותו טיפוס עבור תעודת‬
‫זהות של קטין ועבור תעודת זהות של מבוגר? השתמש במחלקה המייצגת את הטיפוס‬
‫תאריך)‪ (MyDate‬אותה פיתחת בתרגיל ‪ 9‬או במחלקה ‪ Date‬הבנויה ב‪.Java-‬‬
‫ב‪ .‬הוסף את הפעולות הבאות למחלקות המתאימות‪ .‬ציין לכל פעולה לאיזו מחלקה היא שייכת‪ ,‬ותן‬
‫‪ .1‬הוסף‪-‬ילד‪-‬להורה‬
‫דוגמה לזימון הפעולה‪.‬‬
‫‪ .2‬הוצא‪-‬קטין‪-‬שהפך‪-‬מבוגר‪-‬מתעודת‪-‬הורה‪.‬‬
‫‪ .3‬החזר‪-‬מספר‪-‬ילדים‪-‬משותפים‪-‬לשני‪-‬מבוגרים‬
‫ג‪ .‬כתוב פעולה ראשית הבונה עצמים של ‪ 10‬קטינים‪ ,‬ומערך של ‪ 5‬מבוגרים‪ .‬הפעולה משייכת את‬
‫הקטינים להוריהם ומציגה כפלט את זוגות המבוגרים שיש להם ילדים משותפים‪ .‬כל זוג שיש לו‬
‫ילדים משותפים יופיע בפלט פעם אחת‪.‬‬
‫עיצוב תוכנה – טיפוס מורכב‬
‫©‬
‫כל הזכויות שמורות ל'מבט לחלונות'‬
‫‪33‬‬
‫תרגיל ‪ :16‬בניינים ‪‬‬
‫חדר )‪ (Room‬הוא טיפוס נתונים המאופיין על‪-‬ידי סוג החדר(למשל‪ :‬סלון‪ ,‬חדר‪-‬שינה‪ ,‬חדר‪-‬ילדים‪,‬‬
‫חדר‪-‬עבודה‪ ,‬מטבח‪ ,‬אמבטיה וכו')‪ ,‬אורך החדר ורוחב החדר‪.‬‬
‫דירה )‪ (Apartment‬הוא טיפוס נתונים המאופיין על‪-‬ידי שם בעל הדירה ואוסף החדרים של הדירה –‬
‫עד ‪ 10‬חדרים‪.‬‬
‫בניין )‪ (Building‬הוא טיפוס נתונים המאופיין על‪-‬ידי כתובת הבניין והדירות המצויות בו – עד ‪100‬‬
‫דירות‪.‬‬
‫א‪ .‬הגדר במחלקה ‪ Room‬את תכונות הטיפוס חדרושתי פעולות בונות‪ :‬פעולה בונה אחת המקבלת‬
‫את ערכי התכונות כפרמטרים ופעולה בונה מעתיקה‪.‬‬
‫ב‪ .‬הוסף למחלקה ‪ Room‬פעולה המחזירה את שטח החדר‪.‬‬
‫ג‪ .‬הגדר במחלקה ‪ Apartment‬את תכונות הטיפוס דירה וכן פעולה בונה‪.‬‬
‫ד‪ .‬הגדר במחלקה ‪ Building‬את תכונות הטיפוס בניין‪ .‬הנח כי מוגדר טיפוס כתובת )‪)Address‬‬
‫הבנוי מ‪ 3-‬תכונות‪.street, number, city :‬‬
‫ה‪ .‬הוסף את הפעולות הבאות‪ .‬לכל פעולה ציין לאיזו מחלקה של טיפוס היא שייכת‪ ,‬או למחלקה‬
‫‪, )get‬פעולות‬
‫הראשית‪ .‬הנח כי בכל מחלקה של טיפוס קיימות פעולות מאחזרות (שם‪-‬תכונה‬
‫קובעות שם‪-‬תכונה‪ )set‬והפעולה ‪.toString‬‬
‫‪ .1‬חישוב והדפסת השטח הכולל של דירה‪.‬‬
‫‪ .2‬החזרת קטגוריה של גודל הדירה‪ -small :‬עבור דירה שגודלה עד (כולל) ‪ 70‬מ"ר‪medium ,‬‬
‫– עבור דירה שגודלה עד ‪ 110‬מ"ר וכולל‪ – large ,‬עבור דירה שגודלה מעל ‪ 110‬מ"ר‪.‬‬
‫‪ .3‬הדפסת כתובת הבניין‪/‬ים שיש בו הכי הרבה דירות גדולות השייכות לקטגוריה ‪ ,large‬וכן‬
‫שמות בעלי דירות אלה‪.‬‬
‫תרגיל ‪ :17‬מגדל של קוביות ‪‬‬
‫מגדל‪-‬של‪-‬‬
‫הטיפוס קובייה )‪ (Cube‬מאופיין על‪-‬ידי אורך צלע של קובייה וצבע הקובייה‪ .‬הטיפוס‬
‫קוביות )‪ (CubesTower‬מאופיין על‪-‬ידי מספר הקוביות המקסימלי שמגדל יכול להכיל‪ ,‬מספר‬
‫הקוביות שמגדל מסוים מכיל בפועל ואוסף הקוביות המונחות אחת‪-‬על השנייה‪.‬‬
‫על הטיפוס מגדל‪-‬של‪-‬קוביות )‪ (CubesTower‬מוגדרות הפעולות החישוביות הבאות‪:‬‬
‫‪ .1‬הוספת קובייה למגדל (אם המגדל אינו בתפוסתו המקסימלית)‪.‬‬
‫‪ .2‬הסרת קובייה מראש המגדל (אם יש במגדל לפחות קובייה אחת)‪.‬‬
‫‪ .3‬בדיקה האם צבע מסוים מופיע בקובייה במגדל‪.‬‬
‫‪ .4‬בדיקה האם המגדל ריק‪.‬‬
‫‪ .5‬בדיקה האם המגדל נמצא בתפוסתו המקסימלית‪.‬‬
‫א‪ .‬בנה מחלקה לטיפוס קובייה )‪ (Cube‬הכוללת את תכונות הקובייה‪ ,‬פעולה בונה‪ ,‬פעולות קובעות‪,‬‬
‫‪ ,)toString‬ואת הפעולה‬
‫פעולות מאחזרות‪ ,‬פעולה המחזירה מחרוזת המתארת את הקובייה (‬
‫‪ equals‬המחזירה אמת אם שתי קוביות זהות‪ ,‬או שקר אחרת‪.‬‬
‫ב‪ .‬בנה מחלקה לטיפוס מגדל‪-‬של‪-‬קוביות )‪ (CubesTower‬הכוללת את תכונות המגדל‪ ,‬פעולה בונה‪,‬‬
‫פעולות מאחזרות‪ ,‬פעולות קובעות‪ ,toString ,‬את הפעולה ‪ equals‬המחזירה אמת אם שני מגדלים‬
‫זהים‪ ,‬או שקר אחרת ואת הפעולות החישוביות שפורטו לעיל‪.‬‬
‫‪34‬‬
‫עיצוב תוכנה – טיפוס מורכב‬
‫©‬
‫כל הזכויות שמורות ל'מבט לחלונות'‬
‫ג‪ .‬בנה מחלקה ראשית המכילה פעולה ראשית הבונה מגדל‪-‬של‪-‬קוביות שגודלו המקסימלי מתקבל‬
‫‪ -1‬הוספת‬
‫כקלט‪ .‬הפעולה הראשית תקלוט מהמשתמש את הפעולה אותה הוא רוצה לבצע‪:‬‬
‫קובייה למגדל או ‪ -2‬הסרת קובייה מהמגדל‪ ,‬ותפעיל אותה על המגדל‪ .‬הקלט יסתיים כאשר ייקלט‬
‫מספר פעולה ‪ 0‬או כאשר לא ניתן לבצע פעולה מסוימת‪ .‬במקרה שלא ניתן לבצע פעולה מסוימת‬
‫יש להדפיס הודעה מתאימה‪ .‬לאחר כל פעולה יש להדפיס את המגדל‪.‬‬
‫ד‪ .‬מעוניינים להוסיף את הפעולה מגדל‪-‬צבעים‪-‬ייחודים‪ .‬הפעולה תבנה מגדל חדש ממגדל נתון‪.‬‬
‫במגדל החדש תופיע רק קובייה אחת מכל צבע שקיים במגדל הנתון‪ .‬בסוף הפעולה המגדל הנתון‬
‫יישאר ללא קוביות‪ .‬הפעולה תחזיר את המגדל החדש‪ .‬ממש את הפעולה בשני אופנים‪ :‬הראשון –‬
‫במחלקה מגדל‪-‬של‪-‬קוביות והשני – במחלקה הראשית‪ .‬כתוב זימון לכל אחת מהפעולות‪.‬‬
‫תרגילים‪ :‬רגע של גרפיקה – באתר האינטרנט‬
‫כתוב מחלקה‬
‫פרויקטים מסכמים בתכנות מונחה עצמים‬
‫תרגיל ‪ :18‬טלפון סלולרי – תרגיל סיכום ‪ II‬‬
‫‪60‬‬
‫מאפייני טלפון סלולארי הם‪ :‬מספר הטלפון‪ ,‬שם בעל הטלפון‪ ,‬תעודת זהות של בעל הטלפון‪,‬‬
‫שיחות נכנסות אחרונות‪ 60 ,‬שיחות יוצאות אחרונות‪ 60 ,‬הודעות נכנסות אחרונות‪ 60 ,‬הודעות יוצאות‬
‫אחרונות‪ ,‬וספר טלפונים בגודל של ‪ 200‬מספרים‪.‬‬
‫שיחה נכנסת מאופיינת על‪-‬ידי‪ :‬תאריך‪ ,‬שעה‪ ,‬מספר הטלפון ממנו התקבלה השיחה‪.‬‬
‫שיחה יוצאת מאופיינת על‪-‬ידי‪ :‬תאריך‪ ,‬שעה‪ ,‬מספר הטלפון אליו הופנתה השיחה‪.‬‬
‫הודעה נכנסת מאופיינת על‪-‬ידי‪ :‬תאריך‪ ,‬שעה‪ ,‬מספר הטלפון ממנו התקבלה ההודעה ותוכן ההודעה‪.‬‬
‫הודעה יוצאת מאופיינת על‪-‬ידי‪ :‬תאריך‪ ,‬שעה‪ ,‬מספר הטלפון אליו נשלחה ההודעה ותוכן ההודעה‪.‬‬
‫איש קשר בספר טלפונים מאופיין על‪-‬ידי‪ :‬שם‪ ,‬מספר טלפון‪ ,‬וקטגוריה ( בית‪/‬נייד‪/‬אחר)‪.‬‬
‫במחלקה הראשית יש פעולה ראשית הבונה מערך של ‪ 50‬טלפונים סלולאריים‪ .‬כמו‪-‬כן הפעולה קולטת‬
‫את מספר הפעולה המבוקשת )‪ ,(1-4‬מפעילה אותה‪ ,‬ומעדכנת את תכונות המכשירים בהתאם‪ .‬הנח כי‬
‫הפעולות מתבצעות בין שני טלפונים הנמצאים במערך‪.‬‬
‫הפעולות האפשריות הן ‪ )1 :‬חייג‪-‬למספר‪-‬טלפון‪ )2 ,‬קבל‪-‬שיחת‪-‬טלפון‪ )3 ,‬שלח‪-‬הודעה‪ )4 ,‬קבל‪-‬הודעה‪.‬‬
‫א‪.‬‬
‫ב‪.‬‬
‫ג‪.‬‬
‫ד‪.‬‬
‫ה‪.‬‬
‫רשום תרשימי ‪ UML‬לכל אחד מהטיפוסים הדרושים ‪ .‬חשוב על אפיון יעיל‪.‬‬
‫בנה מחלקה לכל אחד מהטיפוסים‪.‬‬
‫בנה מחלקה ראשית ובה פעולה ראשית המבצעת את המשימות שפורטו בשאלה‪.‬‬
‫הוסף פעולה בוליאנית המקבלת ‪ 2‬טלפונים סלולאריים ובודקת האם הייתה התקשרות כלשהי‬
‫בין שני הטלפונים‪ .‬ציין לאיזו מחלקה יש להוסיף פעולה זו‪.‬‬
‫הפעל מהפעולה הראשית את הפעולה שכתבת בסעיף ד עבור כל שני טלפונים הנמצאים במערך‬
‫הטלפונים‪ ,‬והצג כפלט עבור כל זוג את מספרי הטלפון‪ ,‬ואת הערך המוחזר מהפעולה‪.‬‬
‫עיצוב תוכנה – טיפוס מורכב‬
‫©‬
‫כל הזכויות שמורות ל'מבט לחלונות'‬
‫‪35‬‬
‫תרגיל ‪ :19‬חניונים – תרגיל סיכום ‪I‬‬
‫‪‬‬
‫תכנה חדשנית לניהול חניונים דרך האינטרנט של חברת "חנה וסע" מאפשרת למנוייה להזמין מקום‬
‫חניה דרך האינטרנט לשעה מסוימת‪ ,‬תוך ציון משך הזמן המשוער‪ .‬ניתן להזמין מקומות חנייה רק‬
‫לאותו יום ובשעה עגולה‪ .‬בסופו של יום מתרוקנים כל החניונים‪ .‬אדם שמזמין חניה מקבל תשובה‬
‫המציינת אם ההזמנה ניתנת למימוש‪ .‬אם הזמנה אכן ניתנת למימוש – נשמר לאותו אדם מקום חנייה‬
‫מסוים בשעה הנדרשת‪ .‬מקום החניה נשמר ללקוח בשעה זו‪ ,‬כלומר הופך להיות מקום חניה תפוס‪.‬‬
‫במקרה שהמנוי הזמין מקום חניה ולא הגיע לחניון‪ ,‬המקום נשמר למשך שעה עבורה הוא מחויב‬
‫בתשלום‪ .‬במקרה שהמנוי מימש את הזמנתו – התשלום מתבצע בהתאם לזמן ההזמנה (ולא מזמן‬
‫ההגעה)‪ .‬למימוש מערכת זו מוגדרים הטיפוסים‪ :‬כתובת‪ ,‬מנוי‪ ,‬הזמנה‪ ,‬חניון‪ ,‬מערכת חניונים‪.‬‬
‫להלן דיאגרמת תרשים לכל אחד מהטיפוסים‪ .‬הנח כי לכל אחד מהטיפוסים קיימות פעולות בונות‪,‬‬
‫קובעות מאחזרות והפעולה ‪.toString‬‬
‫הטיפוס‬
‫הטיפוס‬
‫תכונות‬
‫כתובת‬
‫רחוב מטיפוס מחרוזת‬
‫מספר מטיפוס שלם‬
‫מטיפוס מחרוזת‬
‫עיר‬
‫מנוי‬
‫תכונות‬
‫מטיפוס מחרוזת‬
‫שם‬
‫מטיפוס מחרוזת‬
‫ת‪.‬ז‪.‬‬
‫כתובת מטיפוס כתובת‬
‫סכום‪-‬לתשלום מטיפוס ממשי‬
‫פעולות‬
‫הוסף‪-‬תשלום(סכום‪-‬תשלום)‬
‫ביצוע‪-‬תשלום‬
‫הטיפוס‬
‫הזמנה‬
‫הטיפוס‬
‫תכונות‬
‫מספר‪-‬הזמנה מטיפוס שלם‬
‫מנוי מטיפוס מנוי‬
‫מספר‪-‬רכב מטיפוס מחרוזת‬
‫מספר‪-‬חניון מטיפוס שלם‬
‫שעת‪-‬התחלה‪-‬משוערת מטיפוס שלם‬
‫מטיפוס שלם‬
‫שעת‪-‬סיום‪-‬משוערת‬
‫שעת‪-‬סיום מטיפוס ממשי‬
‫מקום‪ -‬חניה מטיפוס שלם‬
‫סטטוס‪-‬ביצוע מטיפוס בוליאני‬
‫פעולות‬
‫בצע‪-‬הזמנה()‬
‫החזר‪-‬סכום‪-‬לתשלום‪-‬עבור‪-‬הזמנה()‬
‫הטיפוס‬
‫תכונות‬
‫כתובת מטיפוס מחרוזת‬
‫מטיפוס מחרוזת‬
‫ת‪.‬ז‪.‬‬
‫רשימת הזמנות מטיפוס מערך של הזמנה‬
‫מערך‪-‬מקומות‪-‬חניה מטיפוס מערך בוליאני‬
‫תעריף‪-‬שעת‪-‬חניה מטיפוס ממשי‬
‫פעולות‬
‫האם‪-‬הזמנה‪-‬ניתנת למימוש(מספר‪-‬הזמנה)‬
‫הוסף‪-‬הזמנה(הזמנה)‬
‫עדכן‪-‬מקומות‪-‬חניה‪-‬להזמנות (שעה‪-‬נוכחית)‬
‫(שעה‪-‬נוכחית)‬
‫בטל‪-‬הזמנות‪-‬שלא‪-‬מומשו‬
‫שחרור‪-‬רכב (מספר‪-‬רכב‪ ,‬שעה‪-‬נוכחית)‬
‫החזר‪-‬סכום‪-‬לתשלום‪-‬עבור‪-‬חניה(מספר‪-‬הזמנה)‬
‫מערכת חניונים‬
‫תכונות‬
‫מערך‪-‬מנויים‬
‫מספר‪-‬מנויים‬
‫מערך‪-‬חניונים‬
‫פעולות‬
‫הוסף‪-‬מנוי (מנוי)‬
‫מחק‪-‬מנוי(מנוי)‬
‫האם‪-‬מנוי‪-‬קיים(מנוי)‬
‫‪36‬‬
‫חניון‬
‫מטיפוס מערך של מנוי‬
‫מטיפוס שלם‬
‫מטיפוס מערך של חניון‬
‫עיצוב תוכנה – טיפוס מורכב‬
‫©‬
‫כל הזכויות שמורות ל'מבט לחלונות'‬
‫א‪.‬‬
‫ממש את הפעולה בצע‪-‬הזמנה() שבמחלקה הזמנה‪ .‬הפעולה מתבצעת כאשר רכב מגיע לחניון‪.‬‬
‫הפעולה מעדכנת את סטאטוס הביצוע של ההזמנה ל‪ . true -‬כתוב הוראת זימון לפעולה וציין‬
‫מאיזו מחלקה יתבצע זימון זה‪.‬‬
‫ב‪.‬‬
‫ממש את הפעולה עדכן‪-‬מקומות‪-‬חניה‪-‬להזמנות(שעה‪-‬נוכחית) שבמחלקה חניון‪ .‬הפעולה מעדכנת‬
‫את מקומות החניה שהוזמנו לשעה‪-‬נוכחית זו להיות תפוסים‪ .‬כתוב הוראת זימון לפעולה וציין‬
‫מאיזו מחלקה יתבצע זימון זה‪.‬‬
‫ג‪.‬‬
‫ממש את הפעולה שחרור‪-‬רכב שבמחלקה חניון‪ .‬הפעולה מעדכנת את מקום החניה של הרכב‬
‫להיות פנוי‪ ,‬מעדכנת את שעת הסיום‪ ,‬ומוסיפה למנוי את הסכום לתשלום‪.‬‬
‫ממש את הפעולה בטל‪-‬הזמנות‪-‬שלא‪-‬מומשו(_שעה‪-‬נוכחית) שבמחלקה חניון‪ .‬הפעולה בודקת אלו‬
‫הזמנות לא מומשו (אלה פעולות שעברה שעה מזמן ההתחלה המשוער ועדיין לא הגיעו)‪ .‬הפעולה‬
‫מפעילה על מכוניות שהזמנותיהן לא מומשו את הפעולה שחרור‪-‬רכב(מספר_רכב‪_ ,‬שעת_יציאה)‪.‬‬
‫במחלקה הראשית מוגדרת הפעולה קליטת‪-‬הזמנות‪ .‬להלן אלגוריתם כללי לביצוע הליך זה‪:‬‬
‫ד‪.‬‬
‫ה‪.‬‬
‫קליטת‪-‬הזמנות(_מערכת_חניונים)‬
‫כל עוד יש הזמנות בצע‪:‬‬
‫ קלוט מספר ת‪.‬ז‪ .‬של מנוי‪ .‬אם המנוי לא קיים במאגר המנויים בנה עצם מטיפוס מנוי והוסף‬‫אותו למאגר המנויים‪.‬‬
‫ קלוט את פרטי ההזמנה ההתחלתיים‪ :‬מספר‪-‬רכב‪ ,‬שעת‪-‬התחלה‪-‬משוערת‪ ,‬שעת‪-‬סיום‪-‬‬‫משוערת ומספר חניון‪ .‬אם לא ידוע מספר החניון‪ ,‬קלוט כתובת מבוקשת והפעל את הפעולה‬
‫החזר‪-‬מספר‪-‬חניון‪-‬הקרוב‪-‬ביותר‪-‬לכתובת(_כתובת) הנמצאת בטיפוס מערכת‪-‬חניונים‪.‬‬
‫ בנה עצם מטיפוס הזמנה‪ .‬אם ההזמנה ניתנת למימוש הוסף אותה לרשימת ההזמנות של‬‫החניון‪ .‬הדפס הודעה מתאימה אם ההזמנה ניתנת למימוש או לא‪.‬‬
‫ממש פעולה זו ב‪ Java-‬וכן את הפעולות הדרושות כפי שפורטו לעיל‪.‬‬
‫ו‪ .‬הוסף למחלקה הראשית פעולה המדפיסה לכל חניון את מספר המקומות הפנויים‪.‬‬
‫עיצוב תוכנה – טיפוס מורכב‬
‫©‬
‫כל הזכויות שמורות ל'מבט לחלונות'‬
‫‪37‬‬
‫‪ ‬טיפוס מורכב (‪ – )Composed class‬טיפוס המוגדר על ידי המשתמש שחלק מן התכונות שלו הן‬
‫מטיפוס שאינו בסיסי בשפה אשר הוגדר על ידי המשתמש או שהוא כלול בספריות של השפה‪.‬‬
‫ העקרונות והיתרונות של תכנות מונחה עצמים באים לידי ביטוי כאשר יש שילוב ושימוש במספר‬‫טיפוסים כמו למשל בדוגמה של השילוב בין הטיפוסים‪ :‬תלמיד‪ ,‬מורה‪ ,‬כיתה‪ ,‬ביה"ס‪.‬‬
‫‪ ‬כללי הפיתוח של טיפוס מורכב הם בדיוק כמו כללי הפיתוח של כל טיפוס‪:‬‬
‫‪‬‬
‫הגדרת תכונות שחלקן מטיפוסים לא בסיסיים שהוגדר על‪-‬ידי המשתמש או נמצאים‬
‫בספריות השפה‪.‬‬
‫פעולה בונה ‪ -‬אם פעולה בונה מקבלת את ערכי התכונות כפרמטרים‪ ,‬יש ליצור קודם את‬
‫העצמים המהווים ערכים לתכונות בעצם המורכב שנבנה‪ ,‬ולשלוח אותם כפרמטרים‬
‫המתאימים לפעולה הבונה של העצם המורכב‪.‬‬
‫פעולות מאחזרות – לכל תכונה תוגדר פעולה מאחזרת כך גם לתכונות שהטיפוס שלהן אינו‬
‫בסיסי‪ .‬במקרים אלה יוחזר עצם שהוא ערך התכונה‪.‬‬
‫פעולות קובעות ‪ -‬לכל תכונה תוגדר פעולה קובעת‪ ,‬כך גם לתכונות שהטיפוס שלהן הוגדר על‪-‬‬
‫ידי המשתמש‪ .‬במקרים אלה תקבל הפעולה עצם שהוא הערך החדש של התכונה‪.‬‬
‫‪‬‬
‫‪‬‬
‫‪‬‬
‫‪ ‬מערך של עצמים‬
‫שימוש במערך של עצמים יכול להיות כמשתנה בפעולה וגם כתכונה של טיפוס חדש‪ .‬אין הבדל‬
‫אם מערך העצמים משמש כמשתנה מקומי (בפעולה הראשית או בכל פעולה אחרת) או כתכונה‬
‫של עצם‪.‬‬
‫למרות עקרון זה יש הבדלים הניכרים במרכיבים הבאים‪:‬‬
‫(‪ )1‬בדרך הפנייה אל משתנה או אל תכונה (פנייה ישירה‪ ,‬או פנייה אל העצם שזו התכונה שלו)‪.‬‬
‫(‪ )2‬בדרך הגדרת הפעולות – פעולות סטטיות יקבלו את המערך כפרמטר‪ ,‬פעולות המוגדרות‬
‫בטיפוס המייצג ישות לא יהיו סטטיות‪ ,‬וגם לא יקבלו את המערך כפרמטר‪ .‬פעולות אלו יופעלו על‬
‫עצם שהמערך הוא אחת התכונות שלו ולכן אין צורך בפרמטר‪.‬‬
‫‪ ‬שלבים בפתרון בעיה בתכנות מונחה עצמים‪:‬‬
‫‪‬‬
‫‪‬‬
‫‪‬‬
‫‪‬‬
‫זיהוי העצמים הנדרשים לפתרון הבעיה‪.‬‬
‫אפיון הטיפוסים של העצמים (טיפוסים המייצגים ישויות)‪.‬‬
‫פיתוח כל טיפוס בנפרד (תכונות‪ ,‬פעולות)‪.‬‬
‫פיתוח המחלקה הראשית ובה הפעולה הראשית שבה מופיע האלגוריתם הראשי לפתרון‬
‫הבעיה‪ .‬לשרות הפעולה הראשית יכולות להיות מוגדרות גם פעולות סטטיות אחרות‬
‫במחלקה הראשית‪.‬‬
‫‪38‬‬
‫עיצוב תוכנה – טיפוס מורכב‬
‫©‬
‫כל הזכויות שמורות ל'מבט לחלונות'‬