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

Transcription

פרק לדוגמה - מבט לחלונות
‫פרק‬
‫‪1‬‬
‫מהו טיפוס מורכב?‬
‫עד כה השתמשנו במושג טיפוס בשני הקשרים‪ :‬לפני שנחשפנו למושגים של תכנות מונחה עצמים‬
‫‪ ,)int‬משתנה‬
‫דיברנו על טיפוס בהקשר של סוג הערך של משתנים‪ .‬למשל‪ :‬משתנה מטיפוס שלם (‬
‫מטיפוס ממשי ( ‪ ,)double‬משתנה מטיפוס בוליאני ( ‪ .)bool‬במסגרת תכנות מונחה עצמים דיברנו על‬
‫הגדרת טיפוס על ידי המשתמש‪ ,‬למשל‪ :‬הטיפוסים תלמיד ( ‪ )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‬‬
‫‪ :‬הטיפוס בנקודת המעוין משתמש בטיפוס שהקו מתחיל ממנו‪.‬‬
‫משמעות הקו‬
‫הסבר‪ :‬לטיפוס בנקודת המעוין קימת לפחות תכונה אחת מטיפוס המוצא‪.‬‬
‫לדוגמה קו ‪ – 1‬בטיפוס כיתה יש תכונה המשתמשת בטיפוס מורה‪ :‬התכונה מחנך מטיפוס מורה‪.‬‬
‫הטיפוס בנקודת המעוין משתמש בטיפוס שהקו מתחיל ממנו שלא בתור תכונה‪.‬‬
‫משמעות הקו‬
‫הטיפוס‬
‫תלמיד‬
‫הטיפוס‬
‫מורה‬
‫תכונות‬
‫שם מטיפוס מחרוזת‬
‫ת‪.‬ז‪ .‬מטיפוס מחרוזת‬
‫ציון במתמטיקה מטיפוס שלם‬
‫מטיפוס שלם‬
‫ציון באנגלית‬
‫מטיפוס שלם‬
‫ציון בלשון‬
‫תכונות‬
‫שם מטיפוס מחרוזת‬
‫ת‪.‬ז‪ .‬מטיפוס מחרוזת‬
‫ותק בהוראה מטיפוס שלם‬
‫בעל תעודת הוראה מטיפוס בוליאני‬
‫מקצועות הוראה מטיפוס מערך מחרוזות‬
‫פעולות‬
‫העלה‪-‬ציון(_מקצוע‪_ ,‬נקודות)‬
‫החזר‪-‬ממוצע( )‬
‫הדפס‪-‬תעודה( )‬
‫פעולות‬
‫הגדל‪-‬ותק‪-‬בשנה( )‬
‫הוסף‪-‬מקצוע‪-‬הוראה(_מקצוע)‬
‫האם‪-‬מלמד‪-‬מקצוע(_מקצוע)‬
‫‪2‬‬
‫הטיפוס‬
‫כיתה‬
‫תכונות‬
‫מטיפוס תו‬
‫שכבה‬
‫מטיפוס שלם‬
‫מספר‬
‫מטיפוס מורה‬
‫מחנך‬
‫מספר תלמידים מטיפוס שלם‬
‫מטיפוס מערך של תלמידים‬
‫תלמידים‬
‫פעולות‬
‫הוסף‪-‬תלמיד(_תלמיד)‬
‫קבע‪-‬מחנך(_מורה)‬
‫האם‪-‬תלמיד‪-‬לומד‪-‬בכיתה(_תלמיד)‬
‫החזר‪-‬תלמיד‪-‬מצטיין( )‬
‫הטיפוס‬
‫‪4‬‬
‫הערה‪ :‬התרשים כולל הגדרת תכונות מלאה‬
‫והגדרת פעולות חלקית‪ .‬אין למשל פעולות בונות‪.‬‬
‫‪10‬‬
‫עיצוב תוכנה – טיפוס מורכב‬
‫©‬
‫‪1‬‬
‫‪3‬‬
‫בית ספר‬
‫תכונות‬
‫שם‬
‫עיר‬
‫מורים‬
‫כיתות‬
‫פעולות‬
‫הוסף‪-‬תלמיד‪-‬לכיתה(_שכבה‪_ ,‬מספר‪_ ,‬תלמיד)‬
‫הוסף‪-‬מורה(_מורה)‬
‫באיזו‪-‬כיתה‪-‬תלמיד‪-‬לומד(_תלמיד)‬
‫החזר‪-‬תלמיד‪-‬מצטיין( )‬
‫מטיפוס מחרוזת‬
‫מטיפוס מחרוזת‬
‫מטיפוס מערך של מורים‬
‫מטיפוס מערך של כיתות‬
‫כל הזכויות שמורות ל'מבט לחלונות'‬
‫הסבר החיצים בתרשים‪:‬‬
‫קו ‪ – 1‬בטיפוס כיתה יש תכונה המשתמשת בטיפוס מורה‪ :‬התכונה מחנך מטיפוס מורה‪.‬‬
‫קו ‪ – 2‬בטיפוס כיתה יש תכונה המשתמשת בטיפוס תלמיד‪ :‬התכונה תלמידים מטיפוס מערך של‬
‫תלמיד‪.‬‬
‫קו ‪ – 3‬בטיפוס בית ספר יש תכונה המשתמשת בטיפוס מורה‪ :‬התכונה מורים מטיפוס מערך של מורה‪.‬‬
‫קו ‪ – 4‬בטיפוס בית ספר יש תכונה המשתמשת בטיפוס כיתה‪ :‬התכונה כיתות מטיפוס מערך של כיתה‪.‬‬
‫תרשים מסוג זה מתאר את הקשרים שיש בין טיפוסים ומקל מאד על תהליך תכנון הטיפוסים הכולל‬
‫את זיהוי התכונות והפעולות שלהם‪ ,‬ומקל גם על פיתוח הפעולות תוך שימוש בפעולות המוגדרות‬
‫בטיפוסים האחרים‪.‬‬
‫שים ‪ :‬הפעולה החזר‪-‬תלמיד‪-‬מצטיין( ) מוגדרת בשני טיפוסים‪ .‬הפעולה המוגדרת בטיפוס כיתה‬
‫תופעל על עצם מטיפוס כיתה ותחזיר את התלמיד המצטיין בכיתה‪ .‬הפעולה המוגדרת בטיפוס ביה"ס‬
‫תופעל על עצם מטיפוס ביה"ס ותחזיר את התלמיד המצטיין בביה"ס‪ .‬גם בשפת התכנות ניתן להגדיר‬
‫פעולות בעלות שם זהה בטיפוסים שונים‪ .‬מאחר ובזמן הפעלת הפעולה היא תופעל על עצם מסוים‪,‬‬
‫ועצם יכול להיות רק מטיפוס אחד‪ ,‬אין בעיה בזיהוי הפעולה שיש לבצע‪ .‬הפעולה שתתבצע היא זו‬
‫המוגדרת בטיפוס של העצם עליה היא מופעלת‪.‬‬
‫כללי הפיתוח של טיפוס מורכב הם בדיוק כמו כללי הפיתוח של כל טיפוס‪.‬‬
‫נדגים בשלבים פיתוח לטיפוס כיתה ‪ ,StudentClass‬בהנחה שהטיפוסים תלמיד – ‪ ,Student‬ו מורה –‬
‫‪ Teacher‬מוגדרים‪.‬‬
‫המימוש המלא של הטיפוס המורכב כיתה‪-‬בית ספר‪ :‬בעמוד ‪ 19‬בספר‪.‬‬
‫את הקבצים ניתן לראות באתר האינטרנט בכתובת ‪www.mabatl.co.il‬‬
‫עיין באתר‬
‫אינטרנט‬
‫בחר בקישוריות 'פרויקט כיתה‪-‬פרק ‪'1‬‬
‫בקטגוריה‪ :‬אתרים מלווי ספרים לחץ על‬
‫במהלך הגדרת הטיפוס ניתן דגשים באשר לעצמים המשמשים כערך של תכונה‪ ,‬כערך של פרמטר‪ ,‬או‬
‫כערך מוחזר‪.‬‬
‫דיאגרמת המחלקות שמשתתפות בפרויקט זה היא‪:‬‬
‫‪Student‬‬
‫‪Teacher‬‬
‫‪School‬‬
‫עיצוב תוכנה – טיפוס מורכב‬
‫‪StudentClass‬‬
‫©‬
‫כל הזכויות שמורות ל'מבט לחלונות'‬
‫‪11‬‬
StudentClass ‫ של המחלקה‬UML ‫תרשים‬
StudentClass
private char level
private int number
private Teacher educator
private int numOfStudents
private Student[] students
public StudentClass(char level, int number, Teacher educator, int numOfStudents)
public StudentClass(char level, int number)
public void AddStudent(Student stu)
public char GetLevel()
public int GetNumber()
public int GetNumStudents
public Teacher GetEducator()
public Student GetStudent(string id)
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 bool IsStudentInClass(Student stu)
public bool RaiseGrade(string id, string subject, int points)
‫הגדרת התכונות‬
.‫הגדרת תכונה שהיא מטיפוס אחר של המשתמש מתבצעת בדיוק כמו הגדרה של כל תכונה אחרת‬
.‫תחילה מופיע טיפוס התכונה ואחר כך השם שלה‬
StudentClass ‫הגדרת תכונות המחלקה‬
public class StudentClass
‫ היא‬,educator – ‫ התכונה מחנך‬:‫הסבר‬
{
‫ הערך של התכונה‬.Teacher - ‫מטיפוס מורה‬
char level;
‫כיצד‬
‫ בהמשך נראה‬.‫יהיה עצם מטיפוס מורה‬
int number;
Teacher educator;
.‫תכונה זו מקבלת את הערך שלה‬
int numOfStudents = 0;
‫ היא מערך של‬,students – ‫התכונה תלמידים‬
Student[] students = new Student[30];
,‫ במקרה זה‬.Student – ‫עצמים מטיפוס תלמיד‬
}
,‫ תאי המערך‬30
‫בהגדרת התכונה נבנו גם‬
‫ מוגדרת‬,‫ מאחר ולא בכל כיתה יש מספר תלמידים זהה‬.‫ תלמידים‬30 ‫ בכיתה יכולים להיות עד‬,‫כלומר‬
‫ תכונה זו מייצגת את מספר התלמידים‬.numOfStudents – ‫גם התכונה מספר תלמידים בכיתה‬
‫ הערך של התכונה הזו ינוהל כולו על ידי הפעולות בטיפוס זאת מאחר והוא חייב‬.‫בכיתה מסוימת‬
.‫להיות תואם לתלמידים המושמים במערך התלמידים‬
'‫כל הזכויות שמורות ל'מבט לחלונות‬
©
12
‫עיצוב תוכנה – טיפוס מורכב‬
‫עצמים כערכים של תכונות‬
‫ערכים של משתנים שהם מטיפוס של המשתמש הם עצמים ועל משתנים אלו ניתן להפעיל את‬
‫הפעולות המוגדרות בטיפוס שלהם‪ .‬עצם מטיפוס נקרא גם מופע של הטיפוס‪.‬‬
‫לדוגמה במחלקה ראשית ‪ TestStudent‬ניתן להגדיר מערך של עצמים מטיפוס ‪:Student‬‬
‫;]‪Student[] stu = new Student[30‬‬
‫בדיוק באותו אופן מגדירים ומשתמשים בתכונות שהן מטיפוס של המשתמש‪ ,‬שהערכים שלהן הם‬
‫עצמים‪ .‬למשל בגוף הפעולה הבונה )‪ 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‬‬
‫‪:‬‬
‫‪Jerusalem:‬‬
‫‪Yael‬‬
‫‪200‬‬
‫‪performer:‬‬
‫‪Length‬‬
‫‪sx: Song‬‬
‫‪sy: Song‬‬
‫;‪Song sy = sx‬‬
‫בעקבות ההוראה‪:‬‬
‫תתקבל תמונת הזיכרון הבאה‪:‬‬
‫‪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.name‬‬
‫;‪this.performer = s.performer‬‬
‫;‪this.length = s.length‬‬
‫}‬
‫העמסת פעולות‬
‫הדוגמאות שהוצגו עבור הגדרות שונות לפעולה מתאפשרות עקב המנגנון של העמסת פעולות‬
‫(‪ .)methods overload‬מאחר ויש הבחנה בכותרת של הפעולות‪ ,‬הבאה לידי ביטוי ברשימת‬
‫הפרמטרים שלה‪ ,‬הפעולות יכולות להיות בעלות שם זהה‪ .‬מנגנון זה פועל ביחס לכל סוגי הפעולות‬
‫המוגדרות ולא רק ביחס לפעולה בונה‪.‬‬
‫פעולות מאחזרות‬
‫השימוש בערכים שהם עצמים זהה לשימוש בכל ערך אחר‪ .‬כפי שפעולה יכולה להחזיר ערך מטיפוס‬
‫‪ int‬או ‪ bool‬או ‪ ,string‬היא יכולה להחזיר ערך שהוא עצם מטיפוס ‪ Student‬או מטיפוס ‪ Teacher‬או‬
‫מטיפוס ‪ .StudentClass‬בהתאם לכלל המקובל יש להגדיר פעולה מאחזרת לכל תכונה‪ ,‬בין אם‬
‫התכונה מטיפוס פשוט ובין אם טיפוס התכונה מטיפוס שהוגדר על ידי המשתמש‪ .‬במקרה שהתכונה‬
‫מטיפוס שהוגדר על ידי המשתמש‪ ,‬יוחזר עצם שהוא הערך של התכונה‪.‬‬
‫נסתכל לדוגמה על מספר פעולות מאחזרות שניתן להגדיר בטיפוס כיתה‪:‬‬
‫הפעולה ומשמעותה‬
‫מטרת הפעולה‪ :‬הפעולה מאחזרת את ערך התכונה מחנך‪.‬‬
‫הסבר‪ :‬טיפוס הערך המוחזר על ידי הפעולה הוא ‪Teacher‬‬
‫כטיפוס התכונה ‪ .educator‬כלומר מוחזר עצם מטיפוס מורה‪.‬‬
‫מטרת הפעולה‪ :‬הפעולה מאחזרת את ערך התכונה מערך‬
‫תלמידים‪ .‬הסבר‪ :‬טיפוס הערך המוחזר על ידי הפעולה הוא‬
‫][‪ Student‬כטיפוס התכונה ‪ .students‬כלומר מוחזר עצם מטיפוס‬
‫מערך תלמידים‪.‬‬
‫קוד הפעולה‬
‫)(‪public Teacher GetEducator‬‬
‫{‬
‫;‪return this.educator‬‬
‫}‬
‫)(‪public Student[] GetStudents‬‬
‫{‬
‫;‪return this.students‬‬
‫}‬
‫פעולות קובעות‬
‫מטרת פעולה קובעת היא לקבוע ערך לתכונה‪ .‬באותו אופן בו הפעולה הבונה שהוגדרה לעיל קיבלה‬
‫פרמטר שהערך שלו הוא עצם והשימה אותו בתכונה המתאימה‪ ,‬תוגדר גם הפעולה הקובעת‬
‫המתאימה לתכונה‪ .‬נסתכל לדוגמה על מספר פעולות קובעות שניתן להגדיר בטיפוס כיתה‪:‬‬
‫קוד הפעולה‬
‫הפעולה ומשמעותה‬
‫מטרת הפעולה‪ :‬הפעולה קובעת את ערך התכונה‬
‫מורה‪.‬‬
‫הסבר‪ :‬טיפוס הפרמטר הוא ‪ Teacher‬כטיפוס התכונה‬
‫‪ educator‬שאת הערך שלה קובעת הפעולה‪ ,‬כלומר‪,‬‬
‫מושם בתכונה עצם (כמוסה) מטיפוס מורה‪.‬‬
‫‪16‬‬
‫עיצוב תוכנה – טיפוס מורכב‬
‫©‬
‫‪public void SetEducator(Teacher‬‬
‫)‪educator‬‬
‫{‬
‫;‪this.educator = educator‬‬
‫}‬
‫כל הזכויות שמורות ל'מבט לחלונות'‬
‫מטרת הפעולה‪ :‬הפעולה קובעת את ערך התכונות‪:‬‬
‫מספר תלמידים בכיתה ומערך התלמידים בכיתה‪.‬‬
‫הסבר‪ :‬טיפוס הפרמטר עבור מערך תלמידי הכיתה‬
‫הוא ][‪ Student‬כטיפוס התכונה ‪ students‬שאת הערך‬
‫שלה הפעולה קובעת‪ .‬כלומר מושם בתכונה עצם‬
‫מטיפוס מערך תלמידים‪.‬‬
‫][‪public void SetStudents(Student‬‬
‫)‪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‬‬
‫{‬
‫;]‪Student bestStudent = students[0‬‬
‫)‪for (int i = 1 ; i<this.numOfStudents ; i++‬‬
‫{‬
‫))(‪if bestStudent.Average()>students[i].Average‬‬
‫{‬
‫;]‪bestStudent = students[i‬‬
‫}‬
‫}‬
‫;‪return bestStudent‬‬
‫}‬
‫הסבר‬
‫הפתרון‬
‫הסבר‪ :‬הפעולה תופעל על עצם מטיפוס כיתה‪ .‬הפעולה לא צריכה לקבל פרמטרים לצורך ביצוע‬
‫‪ bestStudent‬מכיל את‬
‫משימת החישוב שלה‪ .‬בגוף הפעולה נסרק מערך התלמידים‪ .‬העצם‬
‫עיצוב תוכנה – טיפוס מורכב‬
‫©‬
‫כל הזכויות שמורות ל'מבט לחלונות'‬
‫‪17‬‬
‫לתלמיד בעל הממוצע הגבוה ביותר שנבדק עד כה‪ .‬בתום סריקת המערך מוחזר התלמיד המתאים‬
‫התלמיד ‪ .bestStudent‬הערך המוחזר על‪-‬ידי הפעולה הוא עצם מטיפוס תלמיד‪ .‬עובדה זו באה‬
‫‪ Student‬המופיע בכותרת‬
‫לידי ביטוי בשני מקומות‪ :‬האחד‪ ,‬בהגדרת טיפוס הערך המוחזר‬
‫הפעולה‪ .‬השני‪ ,‬מאחר והמערך ‪ students‬הוא מערך של תלמידים אזי תא המערך ]‪ students[i‬הוא‬
‫תלמיד‪ .‬שים ‪ :‬מאחר וכל תא במערך הוא מטיפוס תלמיד‪ ,‬ניתן להפעיל על עצם מטיפוס תלמיד‬
‫את הפעולה )(‪ Average‬המוגדרת בטיפוס תלמיד‪ .‬למשל‪ ,‬הזימון )(‪ students[i].Average‬מחזיר‬
‫את ממוצע הציונים של התלמיד שנמצא במערך במקום ‪.i‬‬
‫יתרון משמעותי של המודולאריות‪ ,‬שהיא אחד מעקרונות היסוד של תכנות מונחה עצמים‪ ,‬הוא‬
‫אי‪-‬תלות בייצוג של התכונות‪ .‬למשל‪ ,‬בפרק ‪ ,7‬עודכנו התכונות בטיפוס תלמיד כך שהציונים יהיו‬
‫במערך של ציונים ולא רק ציונים ב‪ 3 -‬מקצועות‪ .‬בהתאמה הוגדרה שם גם פעולה המחשבת את‬
‫הממוצע שחתימתה זהה )(‪ .Average‬כלומר‪ ,‬גם אם בפרויקט ישולב הטיפוס ‪ Student‬המקורי‪,‬‬
‫או הטיפוס ‪ Student‬המורחב למערך ציונים‪ ,‬לא יהיה צורך לשנות דבר בטיפוס כיתה המוגדר‬
‫כאן‪.‬‬
‫פעולות חישוביות המקבלות עצם כפרמטר‬
‫הסבר‬
‫הפתרון‬
‫פעולות חישוביות יכולות לקבל פרמטרים שהערכים שלהם הם עצמים‪ ,‬בדומה לפעולות הקובעות‬
‫המקבלות פרמטר שהוא עצם‪ .‬לדוגמה‪ ,‬פעולה בטיפוס כיתה המקבלת תלמיד ‪ stu‬ומחזירה אמת אם‬
‫התלמיד נמצא בכיתה זו או שקר אם הוא לא נמצא בכיתה זו‪ .‬ההשוואה מתבצעת על פי ת‪.‬ז‪.‬‬
‫)‪public bool IsStudentInClass(Student stu‬‬
‫{‬
‫)‪for (int i=0 ; i<this.numOfStudents ; i++‬‬
‫{‬
‫))(‪if (students[i].GetIdNum()==stu.GetIdNum‬‬
‫;‪return true‬‬
‫}‬
‫;‪return false‬‬
‫}‬
‫הסבר‪ :‬הפעולה תופעל על עצם מטיפוס כיתה שיש לו את התכונה ‪ - students‬מערך של תלמידים‪.‬‬
‫הפעולה סורקת את מערך התלמידים בהתאם למספר התלמידים הנמצא בתכונה ‪numOfStudents‬‬
‫ובודקת האם התלמיד במקום ‪ i‬במערך הוא התלמיד שמספר ת‪.‬ז‪ .‬שלו זהה לתלמיד ‪ stu‬שהתקבל‬
‫בפרמטר‪ .‬אם מספר ת‪.‬ז‪ .‬נמצא מוחזר הערך אמת‪ ,‬אחרת בתום סריקת המערך מוחזר הערך שקר‪.‬‬
‫נסביר בהרחבה את הביטוי הבוליאני‪:‬‬
‫)(‪students[i].GetIdNum() == stu.GetIdNum‬‬
‫על התלמיד ‪stu‬‬
‫הפעל את הפעולה‪:‬‬
‫אחזר מספר ת‪.‬ז‪.‬‬
‫על התלמיד מספר ‪i‬‬
‫במערך התלמידים‬
‫הפעל את הפעולה‪:‬‬
‫אחזר מספר ת‪.‬ז‪.‬‬
‫הפעל את האופרטור ==‬
‫לבדוק האם שני מספרי תעודות‬
‫הזהות (שהם מחרוזות) ‪ -‬זהים‬
‫‪18‬‬
‫עיצוב תוכנה – טיפוס מורכב‬
‫©‬
‫כל הזכויות שמורות ל'מבט לחלונות'‬
‫מחלקה ראשית אינה מייצגת טיפוס נתונים כמו תלמיד או שיר או כיתה או רובוט‪ ,‬אלא מחלקה בה‬
‫מתבצעת משימה‪ .‬במחלקה זו מוגדרים העצמים ומופעלות עליהם פעולות‪ .‬בדומה למחלקה הראשית‬
‫בה בנינו עצמים מטיפוס של המשתמש (פרק ‪ 6‬ביסודות חלק ב)‪ ,‬ובדומה להגדרת מערך של עצמים‬
‫(פרק ‪ 7‬ביסודות חלק ב)‪ ,‬נגדיר מחלקה ראשית שבפעולה הראשית שלה מוגדרים משתנים מטיפוס‬
‫מורכב‪ .‬אין כל שינוי בעקרונות הפיתוח של המחלקה הראשית‪.‬‬
‫דוגמה למחלקה ראשית המגדירה עצמים מטיפוס מורכב‬
‫נגדיר מחלקה ראשית ‪ .Program‬יחד עם מחלקה זו קיימים בפרויקט הטיפוסים‪,Teacher ,Student :‬‬
‫ו‪ .StudentClass -‬הטיפוסים מוגדרים בהתאם לתרשימי ה‪ UML -‬בתחילת הפרק‪ .‬בפעולה הראשית‬
‫של המחלקה ‪ Program‬מתבצע האלגוריתם הבא‪:‬‬
‫‪ )1‬בנה מורה חדש ע"י שימוש בפעולה הבונה )(‪ Teacher‬והשם אותו במשתנה ‪.oneTeacher‬‬
‫‪ )2‬הוסף למורה מקצוע שני כלשהו‪.‬‬
‫‪ )3‬בנה כיתה ע"י שימוש בפעולה הבונה )(‪ StudentClass‬לתוך ‪.class1‬‬
‫‪ )4‬בנה תלמיד ראשון ע"י שימוש בפעולה הבונה )(‪ Student‬והכנס אותו לכיתה ‪.class1‬‬
‫‪ )5‬בנה תלמיד שני ע"י שימוש בפעולה הבונה )(‪ Student‬והכנס גם אותו לכיתה ‪.class1‬‬
‫‪ )6‬הדפס את התעודה של התלמיד המצטיין בכיתה ‪.class1‬‬
‫נציג להלן קטע קוד של המחלקה הראשית ‪.Program‬‬
‫;‪using System‬‬
‫‪class Program‬‬
‫{‬
‫)‪static void Main(string[] args‬‬
‫{‬
‫מייצרים מורה‬
‫;)‪Teacher oneTeacher = new Teacher("Shira more","55555",10,true,"english",3‬‬
‫מוסיפים למורה מקצוע ;)"‪oneTeacher.AddSubject("grammer‬‬
‫מייצרים כיתה עם המורה‬
‫;)‪StudentClass class1 = new StudentClass('A', 2,oneTeacher,30‬‬
‫המשמש כמחנך הכיתה‬
‫מוסיפים תלמיד לכיתה ;))‪class1.AddStudent(new Student("Amir cohen","77777",90,90,80‬‬
‫מוסיפים תלמיד נוסף‬
‫‪class1.AddStudent(new Student("Maor levi", "88888", 90, 90, 70b‬‬
‫;)))(‪Console.WriteLine(class1.StudentDetails(class1.BestInClass‬‬
‫מדפיסים את נתוני התלמיד‬
‫המצטיין בכיתה‪.‬‬
‫}‬
‫}‬
‫}‬
‫עיצוב תוכנה – טיפוס מורכב‬
‫©‬
‫כל הזכויות שמורות ל'מבט לחלונות'‬
‫‪19‬‬

‫דוגמה‬
‫פתורה‬
‫בית ספר‬-‫ הטיפוס כיתה‬:1 ‫דוגמה פתורה‬
.‫בית ספר‬-‫להלן הקוד המלא לפרויקט כיתה‬
using System;
using System.Collections.Generic;
‫מחלקה ראשית‬
using System.Text;
namespace BookMabatPage10
{
class Program
{
static void Main(string[] args)
{
Teacher oneTeacher=new Teacher("Shira more","55555",10,true,"english",3);
oneTeacher.AddSubject("grammer");
StudentClass class1 = new StudentClass('A', 2,oneTeacher,30);
class1.AddStudent(new Student("Amir cohen","77777",90,90,80));
if (class1.AddStudent(new Student("Maor levi", "88888", 90, 90, 70)))
{
Console.WriteLine("The next student added to class");
Console.WriteLine(class1.StudentDetails("88888"));
}
else
{
Console.WriteLine("Sorry Maor the class is full");
}
‫דוגמת הרצה‬
if (!class1.IsStudentInClass("77777"))
{
The next student added to class
Console.WriteLine("Student with id:77777 is not in the class"); name:Maor levi,id:88888
math:90 english:90 grammer:70
}
The student before racing english
else
grade
{
cohen,id:77777
Console.WriteLine("The student before racing english grade");name:Amir
math:90 english:90 grammer:80
Console.WriteLine(class1.StudentDetails("77777"));
The student after racing english grade
class1.RaiseGrade("77777", "english", 10);
name:Amir cohen,id:77777
Console.WriteLine("The student after racing english grade"); math:90 english:100 grammer:80
Console.WriteLine(class1.StudentDetails("77777"));
The next student is the best in class:
}
name:Amir cohen,id:77777
Console.WriteLine("The next student is the best in class:");
math:90 english:100 grammer:80
Console.WriteLine(class1.StudentDetails(class1.BestInClass())); class:A2
Console.WriteLine(class1);
educator name:Shira more,id:55555
working years:10 has Diploma:True
}
subects:english grammer
}
students list:
}
name:Amir cohen,id:77777
math:90 english:100 grammer:80
name:Maor levi,id:88888
math:90 english:90 grammer:70
Press any key to continue . . .
'‫כל הזכויות שמורות ל'מבט לחלונות‬
©
20
‫עיצוב תוכנה – טיפוס מורכב‬
using System;
Student ‫המחלקה‬
using System.Collections.Generic;
using System.Text;
namespace BookMabatPage10
{
class Student
{
private string name;
private string id;
private int mathGrade;
private int englishGrade;
private int grammerGrade;
public Student(string name, string id, int mathGrade,int englishGrade, int
grammerGrade)
{
this.name = name;
this.id = id;
this.mathGrade = mathGrade;
this.englishGrade = englishGrade;
this.grammerGrade = grammerGrade;
}
public string GetName()
{
if(subject=="grammer")
return this.name;
{
}
this.grammerGrade+=points;
public string GetId()
return true;
{
}
return this.id;
return false;
}
}
public int GetMathGrade()
public void SetName(string name)
{
{
return this.mathGrade;
this.name = name;
}
}
public int GetEnglishGrade()
public double Average()
{
{
return this.englishGrade;
int sum =
}
this.mathGrade+this.englishGrade+this
public int GetGrammerGrade()
.mathGrade;
{
return sum / 3.0;
return this.grammerGrade;
}
}
public override string ToString()
public bool RaiseGrade(string subject, int
{
points)
string s = "";
{
s += "name:" +
if (subject == "english")
this.name+","+"id:"+this.id+"\n";
{
s += "math:" + this.mathGrade + "
this.englishGrade += points;
english:"
+ this.englishGrade + "
return true;
grammer:"
+ this.grammerGrade + "\n";
}
return s;
if (subject == "math")
}
{
}
this.mathGrade += points;
}
return true;
}
21
'‫כל הזכויות שמורות ל'מבט לחלונות‬
©
‫עיצוב תוכנה – טיפוס מורכב‬
StudentClass ‫המחלקה‬
using System;
}
using System.Collections.Generic;
public string BestInClass()
using System.Text;
{
namespace BookMabatPage10
int i;
{
Student bestStudent = this.students[0];
class StudentClass
for (i = 1; i < this.numStudentes; i++)
{
{
private char level;
if (this.students[i].Average()>
private int number;
bestStudent.Average())
private Teacher educator;
{
bestStudent = this.students[i];
private int numStudentes;
}
private Student[] students;
}
public const int STANDART = 42;
return bestStudent.GetId();
public StudentClass(char level, int number,
}
Teacher educator,int maxStudents)
public bool IsStudentInClass(string id)
{
{
this.level = level;
return GetStudent(id) != null;
this.number = number;
}
this.educator = educator;
public string StudentDetails(string id)
this.numStudentes = 0;
{
this.students = new Student[maxStudents];
Student stu = GetStudent(id);
}
if (stu != null)
public StudentClass(char level, int number)
{
{
return stu.ToString();
this.level = level;
}
this.number = number;
return null;
this.numStudentes = 0;
}
this.students = new Student[STANDART];
private Student GetStudent(string id)
}
{
public char GetLevel()
int i;
{
for (i = 0; i < this.numStudentes; i++)
return this.level;
{
}
if (this.students[i].GetId() == id)
public int GetNumber()
{
{
return this.students[i];
return this.number;
}
}
}
public int GetNumStudents()
return null;
{
}
return this.numStudentes;
public bool RaiseGrade(string id, string subject, int
}
points)
public void SetLevel(char level)
{
{
Student stu = GetStudent(id);
this.level = level;
if (stu == null)
}
{
public void SetEducator(Teacher educator)
return false;
{
}
this.educator = educator;
stu.RaiseGrade(subject, points);
}
return true;
public bool AddStudent(Student stu)
}
{
public override string ToString()
if (this.numStudentes==this.students.Length)
{
{
int i;
return false;
string s = "class:" + this.level + this.number+"\n";
}
s+= "educator "+this.educator;
this.students[this.numStudentes] = stu;
s += "students list:" + "\n";
this.numStudentes++;
for (i = 0; i < this.numStudentes; i++)
return true;
{a
s += this.students[i];
}
return s;
}
'‫} שמורות ל'מבט לחלונות‬
‫עיצוב תוכנה – טיפוס מורכב © כל הזכויות‬
}
22
using System;
Teacher ‫המחלקה‬
using System.Collections.Generic;
using System.Text;
namespace BookMabatPage10
{
class Teacher
{
private string name;
private string id;
private int workingYears;
private bool hasDiploma;
private int numSubjects;
private string[] subjects;
public Teacher (string name, string id,int workingYears,bool hasDiploma,string
firstSubject,int maxSubjects)
{
this.name = name;
this.id = id;
this.workingYears = workingYears;
this.hasDiploma = hasDiploma;
this.subjects = new string[maxSubjects];
this.subjects[0] = firstSubject;
this.numSubjects = 1;
}
public void IncrementWorkingYears()
{
this.workingYears++;
}
public bool AddSubject(string subject)
{
if( this.numSubjects==this.subjects.Length)
{
return false;
}
this.subjects[this.numSubjects] = subject;
this.numSubjects++;
return true;
}
public bool TeachingSubject(string subject)
{
int i;
s += "working years:" + this.workingYears + " has
for (i = 0; i < this.numSubjects; i++)
Diploma:" + this.hasDiploma + "\n";
{
s
+=
"subects:";
if (this.subjects[i] == subject)
for
(i
= 0; i < this.numSubjects; i++)
{
{
return true;
s+=this.subjects[i]+" ";
}
}
}
s += "\n";
return false;
return s;
}
}
public override string ToString()
}
{
}
string s = "";
int i;
s += "name:" + this.name + "," + "id:" + this.id +"\n"
23
'‫כל הזכויות שמורות ל'מבט לחלונות‬
©
‫עיצוב תוכנה – טיפוס מורכב‬
‫כתוב פעולה‬
‫תרגילים לטיפוס המורכב כיתה‪ :‬פעולות‬
‫‪‬‬
‫תרגיל ‪ :1‬הגדרת פעולה בונה נוספת בטיפוס כיתה‬
‫בהנחה שבטיפוס ‪ Teacher‬יש פעולה בונה שהחתימה שלה‪Teacher(string name, string id) :‬‬
‫המקבלת שם ו‪-‬ת‪.‬ז‪ .‬של מורה‪ .‬כתוב פעולה בונה בטיפוס ‪ StudentClass‬המקבלת כפרמטרים את‪:‬‬
‫השכבה של הכיתה‪ ,‬מספר הכיתה‪ ,‬מספר התלמידים בכיתה‪ ,‬שם המחנך של הכיתה ות‪.‬ז‪ .‬של המחנך‪.‬‬
‫הפעולה תאתחל בהתאמה את התכונות‪ :‬שכבה‪ ,‬מספר כיתה‪ ,‬מספר תלמידים בכיתה ומחנך הכיתה‪.‬‬
‫‪‬‬
‫תרגיל ‪ :2‬הגדרת פעולה בונה מעתיקה‬
‫הגדר במחלקה ‪ StudentClass‬פעולה בונה מעתיקה‪.‬‬
‫שים ‪ :‬הפעולה מקבלת עצם מטיפוס ‪.StudentClass‬‬
‫‪‬‬
‫תרגיל ‪ :3‬הגדרת פעולה מאחזרת בטיפוס כיתה‬
‫‪ n‬במערך‬
‫‪ n‬ומחזירה את התלמיד שמיקומו‬
‫הגדר בטיפוס כיתה פעולה המקבלת מספר שלם‬
‫התלמידים‪ .‬הנח כי המספר ‪ n‬תקין ובטווח של מספר התלמידים בכיתה‪ .‬שים לב שהפעולה מחזירה‬
‫ערך מטיפוס תלמיד‪.‬‬
‫תרגיל ‪ :4‬הגדרת פעולה קובעת בטיפוס כיתה‬
‫‪‬‬
‫חושבים‬
‫הגדר בטיפוס כיתה פעולה המקבלת מספר שלם ‪ n‬ותלמיד ‪ stu‬ו קובעת את התלמיד להיות במקום ‪n‬‬
‫במערך התלמידים‪ .‬הנח כי המספר ‪ n‬תקין ובטווח של מספר התלמידים בכיתה‪.‬‬
‫רגע‪..‬‬
‫שאלה למחשבה‪ :‬אם במקום ‪ n‬במערך התלמידים כבר נמצא תלמיד (עצם מטיפוס ‪)Student‬‬
‫מה קורה לו?‬
‫תרגיל ‪ :5‬הגדרה של פעולה בטיפוס כיתה המקבלת עצם כפרמטר ‪‬‬
‫‪‬‬
‫הגדר בטיפוס כיתה פעולה המקבלת עצם מטיפוס מורה ובודקת האם הוא המחנך של הכיתה‪ .‬אם כן‬
‫תחזיר הפעולה אמת‪ ,‬ואם לא תחזיר שקר‪.‬‬
‫תרגיל ‪ :6‬הגדרת פעולה בטיפוס כיתה – המחזירה מערך תלמידים‬
‫‪‬‬
‫בטיפוס כיתה הוגדרה הפעולה )(‪ BestInClass‬אשר מחזירה את התלמיד המצטיין בכיתה‪ .‬התלמיד‬
‫המצטיין הוא התלמיד שהממוצע שלו הגבוה ביותר‪ .‬מה קורה אם יש מספר תלמידים בעלי אותו‬
‫ממוצע? בפעולה שהוגדרה בגוף הפרק יוחזר התלמיד הראשון שימצא‪ .‬איננו רוצים להסתפק בהגדרת‬
‫פעולה זו מאחר ואינה מתאימה למציאות‪ .‬כדי שנוכל להתאים פעולה זו למצב בו יש יותר ממצטיין‬
‫אחד‪ ,‬על הפעולה להחזיר מערך של תלמידים מצטיינים‪ .‬כלומר מערך שיהיו בו כל התלמידים שיש‬
‫להם את הממוצע הגבוה ביותר‪ .‬כתוב פעולה )(‪ BestsInClass‬המחזירה מערך ובו התלמידים בעלי‬
‫הממוצע הגבוה ביותר‪ .‬שים ‪ :‬מה יהיה גודל המערך המוחזר? איך נדע כמה תלמידים יש בו?‬
‫‪24‬‬
‫עיצוב תוכנה – טיפוס מורכב‬
‫©‬
‫כל הזכויות שמורות ל'מבט לחלונות'‬
‫‪‬‬
‫דוגמה‬
‫פתורה‬
‫דוגמה פתורה ‪ :2‬הטיפוס דיסק‬
‫פתח את פרוייקט הדיסק על‪-‬פי כל השלבים שהוצגו בפרק זה‪:‬‬
‫‪ ‬דיאגרמת המחלקות המשתתפות בפרויקט;‬
‫‪ ‬תיאור הטיפוסים בטבלה (הטיפוס שיר והטיפוס דיסק)‬
‫‪ ‬מימוש במחלקות השונות‪ ,‬וכיו"ב‬
‫פתרון‬
‫הפרויקט כולל שלושה טיפוסים‪ :‬הטיפוס שיר הממומש במחלקה ‪ Song‬שהוצג בפרק ‪ 6‬בספר יסודות‬
‫חלק ב‪ ,‬הטיפוס המורכב דיסק הממומש במחלקה ‪ Disc‬שתפותח כאן‪ ,‬והמחלקה הראשית ‪TestDisc‬‬
‫שתפותח כאן‪.‬‬
‫דיאגרמת המחלקות שמשתתפות בפרויקט זה היא‪:‬‬
‫‪Song‬‬
‫‪Disc‬‬
‫‪TestDisc‬‬
‫תיאור הטיפוס שיר‬
‫הטיפוס שיר ( ‪ )Song‬מאפיין שירים ומתייחס אל שלוש תכונות‪ :‬שם השיר‪ ,‬שם המבצע ואורך השיר‬
‫בשניות‪ .‬ניתן כמובן להוסיף תכונות נוספות‪ .‬האיור שלהלן מתאר את הטיפוס שיר וכולל הרחבה‬
‫בסיווג הפעולות‪ .‬כל הפעולות המופיעות באיור יופיעו בהגדרת המחלקה המממשת את הטיפוס‪:‬‬
‫הטיפוס‬
‫שיר‬
‫תכונות‬
‫שם השיר‬
‫שם המבצע‬
‫אורך השיר בשניות‬
‫פעולות‬
‫בונות‬
‫שיר (_שם‪_ ,‬מבצע‪_ ,‬אורך)‬
‫שיר ( ) { פעולה בונה הקולטת ערכים לתכונות }‬
‫מאחזרות‬
‫אחזר שם שיר ( )‬
‫אחזר שם מבצע ( )‬
‫אחזר אורך ( )‬
‫קובעות‬
‫קבע שם שיר (_שם‪) 1‬‬
‫קבע שם מבצע ( _מבצע‪)1‬‬
‫קבע אורך (_אורך‪) 1‬‬
‫חישוביות‬
‫הגדל אורך שיר ב (_מספר_שניות)‬
‫הקטן אורך שיר ב (_מספר_שניות)‬
‫סיווג אורך ()‬
‫{ קצר‪ -‬קטן מ‪ 2 -‬דקות‪,‬‬
‫ארוך‪ -‬ארוך מ‪ 4 -‬דקות‪,‬‬
‫ממוצע – אחרת }‬
‫הדפס פרטי שיר()‬
‫עיצוב תוכנה – טיפוס מורכב‬
‫©‬
‫כל הזכויות שמורות ל'מבט לחלונות'‬
‫‪25‬‬
using System;
Song ‫מימוש המחלקה‬
class Song
{
private string name;
// Name of song
private string performer; // Name of the Performer of the song
‫תכונות‬
private int length;
// Length of song in seconds
public Song(string name, string performer, int length)
{
this.name = name;
this.performer = performer;
this.Length = length;
}
public Song()
{
}
public string GetName()
{
return name;
}
public string GetPerformer()
{
return performer;
}
public int GetLength()
{
return length;
}
public void SetName(string name)
{
this.name = name;
}
public void SetPerformer(string performer)
{
this.performer = performer;
}
public void SetLength(int length)
{
this.Length = length;
}
/ -‫* הפעולה מגדילה את אורך השיר ב‬sec* ‫ שניות‬/
public void IncreaseLength(int sec)
{
Length = Length + sec;
}
/* ‫ שניות‬sec -‫* הפעולה מקטינה את אורך השיר ב‬/
public void DecreaseLength(int sec)
{
Length = Length - sec;
'‫כל הזכויות שמורות ל'מבט לחלונות‬
‫פעולות‬
‫בונות‬
‫פעולות‬
‫מאחזרות‬
‫פעולות‬
‫קובעות‬
‫פעולות‬
‫חישוביות‬
©
26
‫עיצוב תוכנה – טיפוס מורכב‬
}
/
* ‫* הפעולה מחזירה מחרוזת שהיא הקטגוריה של אורך השיר‬
* ‫ ממוצע‬- ‫ אחרת‬,‫ דקות – ארוך‬4 ‫ אם אורכו מעל‬,‫ דקות – קצר‬2 ‫* אם אורכו עד‬/
public string Category()
{
if (Length< 2*60)
return "short";
else
if (Length > 4*60)
return "long";
else
return "average";
}
/* ‫* הפעולה מדפיסה את תכונות השיר‬/
public void DisplaySongDetails()
{
Console.WriteLine("The song name is: " + name);
Console.WriteLine("The preformer is: " + performer);
Console.WriteLine("The song length in seconds is: " + length);
}
}
‫תיאור הטיפוס דיסק‬
-‫ שלהלן (בחלק מתרשימי ה‬UML -‫) מאפיין דיסק של שירים ומתואר בתרשים ה‬Disc( ‫הטיפוס דיסק‬
:)‫ שמוצגים בספר יש עמודה נוספת לצורך תיעוד סוגי הפעולות המוגדרות‬UML
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()
27
'‫כל הזכויות שמורות ל'מבט לחלונות‬
©
‫עיצוב תוכנה – טיפוס מורכב‬
‫בונות‬
‫מאחזרות‬
‫קובעות‬
‫חישוביות‬
‫פעולות‬
‫עיין באתר‬
‫אינטרנט‬
‫הסבר‬
‫הפתרון‬
‫‪-‬‬
‫‬‫‪-‬‬
‫‪-‬‬
‫‪-‬‬
‫המימוש המלא של הטיפוס המורכב דיסק באתר האינטרנט בכתובת ‪www.mabatl.co.il‬‬
‫בקטגוריה‪ :‬אתרים מלווי ספרים לחץ על‬
‫בחר ב 'פרויקט דיסק‪-‬פרק ‪'1‬‬
‫הסבר הקוד (שמוצג באתר)‪:‬‬
‫התכונה מערך שירים היא תכונה ככל התכונות האחרות‪ ,‬ולכן גם עבורה מוגדרות פעולה קובעת‬
‫‪ SetSongs‬המקבלת מערך שירים ומאתחלת את התכונה‪ ,‬ופעולה מאחזרת ‪ GetSongs‬המחזירה‬
‫את התכונה שהיא מערך השירים‪.‬‬
‫‪ Disc‬ולכן אין צורך שיקבלו‬
‫הפעולות המוגדרות בטיפוס הן פעולות שיופעלו על עצם מטיפוס‬
‫כפרמטר את הדיסק או איזו שהיא תכונה שלו‪.‬‬
‫הפעולה המחזירה את מספר השירים לפי קטגוריה )‪,NumberOfSongsInCategory(string c‬‬
‫מקבלת כפרמטר מחרוזת ובה הקטגוריה הנדרשת – קטגוריה זו אינה תכונה של הדיסק או של‬
‫אחד משיריו‪ ,‬לכן היא מתקבלת כפרמטר‪.‬‬
‫בכל הפעולות החישוביות יש התייחסות אל התכונה ‪ songs‬שהיא מערך של שירים‪ .‬כאשר יש פניה‬
‫אל ]‪ ,songs[i‬יש פניה אל עצם מטיפוס ‪ Song‬ועליו ניתן להפעיל פעולות המוגדרות בטיפוס ‪.Song‬‬
‫למשל‪.GetLength() :‬‬
‫מתוך גוף הפעולה המחזירה את מספר השירים לפי קטגוריה‪ ,‬נסביר את ההוראה‪:‬‬
‫)‪if (songs[i].Category()==c‬‬
‫;‪count++‬‬
‫על השיר הנמצא במקום ‪ i‬במערך השירים ‪ ,songs‬מופעלת הפעולה )(‪ .Category‬פעולה זו מוגדרת‬
‫בטיפוס ‪ Song‬ומחזירה מחרוזת ובה הקטגוריה של השיר‪.‬‬
‫מימוש המחלקה הראשית‬
‫הפעולה הראשית במחלקה הראשית ‪ TestDisc‬מממשת את האלגוריתם הבא‪:‬‬
‫‪ )1‬בנה עצם חדש מטיפוס ‪ Disk‬והשם אותו במשתנה ‪.d‬‬
‫‪ )2‬חשב את האורך הכולל של הדיסק ‪ d‬ע"י הפעולה )(‪ DiscLength‬והשם את התוצאה במשתנה‬
‫השלם ‪.totalLength‬‬
‫‪ )3‬הדפס את אורך הדיסק מתוך המשתנה ‪.totalLength‬‬
‫‪ )4‬חשב והדפס את הממוצע של אורך שיר בדיסק ‪ d‬ע"י הפעולה )(‪.AverageSongLength‬‬
‫‪ )5‬חשב והדפס את שם השיר הארוך ביותר בדיסק ‪ d‬ע"י הפעולה )(‪.NameOfLongestSong‬‬
‫‪ )6‬חשב והדפס את מספר השירים ה"קצרים" ע"י הפעולה )"‪.NumberOfSongsInCategory("short‬‬
‫‪28‬‬
‫עיצוב תוכנה – טיפוס מורכב‬
‫©‬
‫כל הזכויות שמורות ל'מבט לחלונות'‬
class TestDisc
{
// ‫הפעולה הראשית‬
public static void Main(string[] args)
{
string songName, performer;
int length;
Console.WriteLine("Enter disc name : ");
string name = Console.ReadLine();
Console.WriteLine("Enter number of songs on disc: ");
Song[] songs = new Song[int.Parse(Console.ReadLine())];
for ( int i=0 ; i<songs.Length ; i++ )
{
Console.WriteLine("Enter song no. "+i+" name : ");
songName = Console.ReadLine();
Console.WriteLine("Enter song no. "+i+" performer : ");
performer = Console.ReadLine();
Console.WriteLine("Enter song no. "+i+" length : ");
length = int.Parse(Console.ReadLine());
songs[i] = new Song(songName, performer,length);
}
Disc d = new Disc(name, songs);
int totalLength = d.DiscLength();
Console.WriteLine("The disc total length is : " + totalLength );
Console.WriteLine ("The average song length is: " + d.AverageSongLength());
Console.WriteLine ("The longest song is: " + d.NameOfLongestSong());
Console.WriteLine ("The number of short songs is: " +
d.NumberOfSongsInCategory("short"));
}
}
‫ באותו אופן‬Disc ‫ בפעולה הראשית נבנה עצם מן הטיפוס המורכב‬:‫הסבר גוף הפעולה הראשית‬
‫ אפשר להפעיל את‬Disc ‫ שהוא מטיפוס‬d ‫ על העצם‬.Song ‫בו נבנו עצמים מטיפוס פשוט כדוגמת‬
.‫הפעולות המוגדרות בטיפוס שלו‬
‫הסבר‬
‫הפתרון‬
‫ על עצמים‬ToString ‫הפעולה‬
:?‫האם ניתן פשוט להדפיס את פרטי הדיסק כך‬
29
'‫כל הזכויות שמורות ל'מבט לחלונות‬
©
‫עיצוב תוכנה – טיפוס מורכב‬
‫חושבים‬
.‫ המדפיסה את כל התכונות של הדיסק‬DisplayDiscDetails() ‫ הוגדרה הפעולה‬Disc ‫במחלקה‬
:‫הפעלה שלה בתכנית הראשית תהיה למשל‬
Console.WriteLine ("The disc details: ");
..‫רגע‬
d.DisplayDiscDetails();
Console.WriteLine (d);
‫הסבר‬
‫הפתרון‬
‫הדפסה כזו תביא להפעלה אוטומטית של הפעולה ‪ ToString‬על הדיסק ‪ .d‬כאשר פעולה זו מופעלת על‬
‫עצם‪ ,‬הפעולה ‪ ToString‬תחזיר למשל את המחרוזת הבאה‪Disc :‬‬
‫במחרוזת זו מופיע שם המחלקה‪ .‬מחרוזת זו אינה המחרוזת בה אנו מעוניינים הכוללת את כל ערכי‬
‫התכונות של הדיסק‪ .‬אם אנו מעוניינים בהדפסה "אוטומטית" כזו עלינו להגדיר מחדש את הפעולה‬
‫‪ ToString‬עבור המחלקה שלנו‪ .‬ההבדל יהיה בכך שכל הפרטים הנדרשים להופיע בפלט ישורשרו‬
‫למחרוזת אחת שתוחזר ע"י הפעולה ‪ ToString‬ואז הוראת הפלט שהוצגה לעיל אמנם תתן את הרצוי‪.‬‬
‫כלומר בכל פעם שנבקש להדפיס עצם מטיפוס ‪ Disc‬תופעל עליו הפעולה ‪ ToString‬המחזירה מחרוזת‬
‫המתארת אותו והיא זו שתודפס‪ .‬נגדיר את הפעולה באופן זה‪:‬‬
‫‪ */‬הפעולה מחזירה מחרוזת המכילה את פרטי הדיסק *‪/‬‬
‫)(‪public override 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‬‬
‫כתוב מחלקה‬
‫תרגילים לטיפוס מורכב‪... :‬‬
‫תרגיל ‪ :7‬הגדרת פעולה בטיפוס דיסק – מספר השירים בכל קטגוריה ‪‬‬
‫הגדר בטיפוס ‪ Disc‬פעולה המחזירה מערך מונים בן ‪ 3‬תאים‪ .‬בתא הראשון יהיה מספר השירים‬
‫הקצרים בדיסק‪ ,‬בתא השני יהיה מספר השירים באורך ממוצע בדיסק‪ ,‬בתא השלישי יהיה מספר‬
‫‪ TestDisc‬לבדיקת‬
‫השירים הארוכים בדיסק‪ .‬הוסף הוראה מתאימה בפעולה הראשית במחלקה‬
‫הפעולה‪.‬‬
‫תרגיל ‪ :8‬שינוי פעולות בטיפוס דיסק – החזרת השיר הארוך ‪‬‬
‫בטיפוס ‪ Disc‬הוגדרו שתי פעולות המבצעות מבחינה אלגוריתמית את אותה המשימה‪ .‬הפעולה‬
‫)(‪NameOfLongestSong‬‬
‫)(‪ MaxSongLength‬מחזירה את אורך השיר הארוך ביותר‪ .‬הפעולה‬
‫מחזירה את שם השיר הארוך ביותר‪ .‬במקום שתי הפעולות האלה הגדר פעולה )(‪TheLongestSong‬‬
‫המחזירה את השיר הארוך ביותר בדיסק‪.‬‬
‫הוסף את ההוראות הבאות בפעולה הראשית במחלקה ‪:TestDisc‬‬
‫‪ )1‬מצא את השיר הארוך ביותר בדיסק על ידי הפעולה )(‪ TheLongestSong‬והשם את השיר ב‪-‬‬
‫‪.maxSong‬‬
‫‪ )2‬הדפס את שם השיר ‪ maxSong‬ואת אורכו‪.‬‬
‫‪30‬‬
‫עיצוב תוכנה – טיפוס מורכב‬
‫©‬
‫כל הזכויות שמורות ל'מבט לחלונות'‬
‫בפרק זה הודגם שימוש במערך של עצמים שהוא תכונה של עצם מטיפוס מורכב (למשל‪ ,‬מערך שירים‬
‫בטיפוס דיסק)‪ .‬בעבר (בספר יסודות מדעי המחשב‪ ,‬חלק ב‪ ,‬פרק ‪ )7‬הודגם שימוש במערך של עצמים‬
‫ששימש כמשתנה בתכנית הראשית‪.‬‬
‫נשאלת השאלה‪ :‬האם יש הבדל בדרך בה אנו משתמשים במערך בשני ההקשרים?‬
‫התשובה היא‪ :‬לא‪.‬‬
‫הטיפול במערך של עצמים הוא זהה בכל מקרה‪ .‬לא חשוב אם מערך העצמים הוא משתנה מקומי‬
‫(בפעולה הראשית או בכל פעולה אחרת) או תכונה של עצם‪.‬‬
‫למרות עקרון זה יש הבדלים הניכרים במרכיבים הבאים‪:‬‬
‫(‪ )1‬בדרך הפנייה אל משתנה או אל תכונה‪.‬‬
‫(‪ )2‬בדרך הגדרת הפעולות – האם הן פעולות סטטיות במחלקה ראשית אשר מקבלות את המערך‬
‫כפרמטר‪ ,‬או שהן פעולות המוגדרות בטיפוס המייצג ישות‪ ,‬ואז הן לא תהיינה סטטיות‪ ,‬וגם לא‬
‫תקבלנה את המערך כפרמטר‪ .‬פעולות אלו תופעלנה על עצם שהמערך הוא אחת התכונות שלו ולכן‬
‫אין צורך בפרמטר‪.‬‬
‫דוגמה לשימוש במערך עצמים כמשתנה או כתכונה‬
‫חלק מן הפעולות שהוגדרו בטיפוס דיסק בפרק זה הוגדרו בספר יסודות חלק ב בפרק ‪ :7‬מערך של‬
‫עצמים‪ ,‬דוגמה ‪ .2‬התייחסו ת למשתנה שהוא מערך של עצמים אשר הוגדר למשל בתכנית הראשית‬
‫‪ .Disc‬האלגוריתמים‬
‫‪ ,SongProgram2‬זהה לטיפול במערך של עצמים שהוא תכונה בטיפוס‬
‫המתייחסים למערך השירים הם אותם אלגוריתמים אך יש הבדלים בדרך הגישה אל מערך השירים‪.‬‬
‫נסתכל ונשווה למשל את הפעולה המחשבת את ממוצע אורכי השירים הנמצאים במערך שירים‬
‫במחלקה ‪ ,SongProgram2‬אל הפעולה המחשבת את ממוצע אורכי השירים של השירים בדיסק‬
‫במחלקה ‪ .Disc‬ברור כי האלגוריתם לביצוע הפעולה הוא זהה‪ .‬בכל מקרה לצורך חישוב הערך‬
‫המוחזר‪ ,‬יש לצבור את אורכי השירים ולחלק במספר השירים‪ .‬ההבדלים באים לידי ביטוי בכותרת‬
‫הפעולה‪ ,‬בשם המערך המיוחס בגוף הפעולה‪ ,‬ובדרך זימון הפעולה‪.‬‬
‫פעולה סטטית שהוגדרה במחלקה ראשית‬
‫כותרת הפעולה‪:‬‬
‫‪public static double‬‬
‫)‪AverageSongLength(Song[] s‬‬
‫ הפעולה היא סטטית כי לא תופעל על עצם‪.‬‬‫ הפעולה מקבלת את מערך השירים כפרמטר‬‫כדי שתוכל להתייחס אל ערכיו‪.‬‬
‫פעולה פנימית שהוגדרה במחלקה ‪Disc‬‬
‫כותרת הפעולה‪:‬‬
‫()‪public double AverageSongLength‬‬
‫ הפעולה אינה סטטית כי היא תופעל על עצם‪.‬‬‫ הפעולה לא מקבלת את מערך השירים כפרמטר כי מערך‬‫השירים הוא תכונה של העצם עליו תופעל הפעולה‪.‬‬
‫עיצוב תוכנה – טיפוס מורכב‬
‫©‬
‫כל הזכויות שמורות ל'מבט לחלונות'‬
‫‪31‬‬
{
:‫גוף הפעולה‬
int sum = 0;
for ( int i = 0 ; i<this.songs.Length ; i++ )
{
sum = sum+ this.songs[i].GetLength();
}
return (double)sum/this.songs.Length;
}
int sum = 0;
for ( int i = 0 ; i<s.Length ; i++)
{
sum = sum+ s[i].GetLength();
}
return (double)sum/s.Length;
}
.‫ האלגוריתם בגוף הפעולה זהה‬‫ הפעולה מתייחסת אל המערך שהוא התכונה של העצם עליו‬.songs ‫ על פי שם התכונה‬,‫הופעלה‬
:‫גוף הפעולה‬
}
.‫ האלגוריתם בגוף הפעולה זהה‬‫ הפעולה מתייחסת אל המערך שהתקבל‬.s ‫כפרמטר‬
:‫זימון הפעולה‬
:‫זימון הפעולה‬
public static void Main(string[] args)
public static void Main(string[] args)
{
string songName, performer;
{
int length;
Song[] songs= InitialSongArray();
Console.WriteLine("Enter disc name : ");
Console.WriteLine("The average
string name = Console.ReadLine();
song length is:
Console.WriteLine("Enter songs no.");
"+AverageSongLength(songs));
songs=newSong[int.Parse(Console.ReadLine())]; }
for ( int i=0 ; i<songs.Length ; i++ )
‫ הפעולה הראשית מוגדרת במחלקה‬{
.SongProgram2
Console.WriteLine("Enter song name: ");
‫ הפעולה הראשית מוגדרת באותה מחלקה בה‬SongName = Console.ReadLine();
Console.WriteLine("Enter song
.AverageSongLength ‫מוגדרת הפעולה‬
performer: ");
‫ שם מערך השירים שהוא משתנה של הפעולה‬performer = Console.ReadLine();
.songs ‫הראשית הוא‬
Console.WriteLine("Enter song length: ");
‫ מערך השירים מאותחל על ידי שירים בעזרת‬length = int.Parse(Console.ReadLine());
‫ שאף היא פעולה‬InitialSongArray() ‫הפעולה‬
songs[i] = new Song(songName,
.SongProgram2 ‫סטטית במחלקה‬
performer,length);
‫ מועבר כפרמטר לפעולה‬songs ‫ המערך‬}
‫ כדי לחשב את ממוצע‬AverageSongLength
Disc d = new Disc(name, songs);
.‫אורכי השירים הנמצאים בו‬
Console.WriteLine ("The average song
length is: "+ d.AverageSongLength());
}
‫ בעוד הפעולה‬.TestDisc ‫ הפעולה הראשית מוגדרת במחלקה‬.Disc ‫ מוגדרת בתוך הטיפוס‬AverageSongLength
‫ ולכן אינו מופיע‬,d ‫ מערך השירים הוא תכונה של הדיסק‬.‫במפורש בגוף הפעולה הראשית‬
‫ מערך השירים מאותחל על ידי שירים בעזרת הפעולה הבונה‬. Disc(name, songs) :‫של דיסק‬
AverageSongLength ‫ אין צורך להעביר אף פרמטר לפעולה‬‫ הפעולה‬.d ‫כדי לחשב את ממוצע אורכי השירים בדיסק‬
.‫ ומערך השירים הוא תכונה שלו‬,‫מופעלת על הדיסק עצמו‬
'‫כל הזכויות שמורות ל'מבט לחלונות‬
©
32
‫עיצוב תוכנה – טיפוס מורכב‬
‫עד כה התייחסנו אל תכונות המאפיינות עצמים‪ .‬לפעמים יש צורך בתכונה המשותפת לכל העצמים‬
‫במחלקה‪ .‬תכונה של מחלקה היא תכונה המוגדרת כ ‪ static‬ושעבורה מוקצה זיכרון רק פעם אחת ואין‬
‫הקצאת זיכרון נפרדת עבור כל עצם שנוצר כמו לגבי התכונות שהכרנו עד כה‪ .‬הערך שלה ברגע מסוים‬
‫זהה לגבי כל העצמים‪ .‬לתכונה זו ניתן לפנות דרך העצמים או דרך המחלקה‪ .‬כל שינוי בתכונה גם אם‬
‫נעשה על ידי עצם אחד של המחלקה חל למעשה לגבי כולם – כי יש לו שטח זיכרון אחד‪.‬‬
‫דוגמה‪ :‬שיוך מספר סידורי לכל עצם שנוצר מן המחלקה‬
‫נניח שאנו מפתחים מבחן ממוחשב‪ .‬כל נבחן מקליד את שמו ומקבל מספר נבחן שהוא מספר סידורי‬
‫עוקב ביחס לכל הנבחנים‪ .‬נסתפק בהגדרת התכונות הבאה עבור כל תלמיד‪ :‬שם‪ ,‬מספר נבחן והמבחן‬
‫עצמו‪ .‬כדי שכל נבחן יקבל מספר אחר ייחוד י לו וגם עוקב לנבחן הקודם‪ ,‬יש להגדיר תכונה משותפת‬
‫תלמיד‪-‬נבחן תקדם את מונה הנבחנים‬
‫לכל הנבחנים‪ ,‬כתכונה סטטית‪ .‬כל בניה של עצם מטיפוס‬
‫מספר‪-‬נבחן של התלמיד‪ .‬להלן חלקים מקוד המחלקות‬
‫הכללי ותציב את ערך המונה לתכונה‬
‫בפרויקט ותוצאות הרצה של הפעולה הראשית‪.‬‬
‫‪ – testCounter‬תכונה של מחלקה ומוגדרת‬
‫כ‪static -‬‬
‫קידום התכונה של המחלקה ‪testCounter‬‬
‫והשמת ערכה לתכונה ‪ num‬המיוחסת לעצם‬
‫שנבנה‬
‫פעולה מאחזרת לתכונה חייבת להיות ‪static‬‬
‫כי היא מתייחסת לתכונה שהיא ‪static‬‬
‫;‪using System‬‬
‫‪public class TestStudent‬‬
‫{‬
‫;‪private static int testCounter = 0‬‬
‫;‪private string name‬‬
‫;‪private int num‬‬
‫)‪TestStudent(string name‬‬
‫{‬
‫;‪this.name = name‬‬
‫;‪testCounter ++‬‬
‫;‪this.num = testCounter‬‬
‫}‬
‫)( ‪public static int GetTestCounter‬‬
‫{‬
‫;‪return testCounter‬‬
‫}‬
‫)(‪public override string ToString‬‬
‫{‬
‫;‪return "name = " + name + " --- " + num‬‬
‫}‬
‫}‬
‫עיצוב תוכנה – טיפוס מורכב‬
‫©‬
‫כל הזכויות שמורות ל'מבט לחלונות'‬
‫‪33‬‬
‫‪public class MainTest‬‬
‫{‬
‫)(‪public static void main‬‬
‫{‬
‫קבלת ערך התכונה‬
‫;)"‪TestStudent s1 = new TestStudent("aaa‬‬
‫‪ testCounter‬דרך המחלקה‬
‫;)"‪TestStudent s2 = new TestStudent("bbb‬‬
‫בלבד לא ניתן דרך עצם כי‬
‫;)"‪TestStudent s3 = new TestStudent("ccc‬‬
‫הוא שייך רק למחלקה‪.‬‬
‫;)‪Console.WriteLine(s1‬‬
‫;)‪Console.WriteLine(s2‬‬
‫;)‪Console.WriteLine(s3‬‬
‫;))(‪Console.WriteLine("testCounter value: " + TestStudent.GetTestCounter‬‬
‫}‬
‫}‬
‫הפלט המתקבל הוא‪:‬‬
‫‪name = aaa --- 1‬‬
‫‪name = bbb --- 2‬‬
‫‪name = ccc --- 3‬‬
‫‪testCounter value: 3‬‬
‫כאשר ניגשים לפתרון בעיה בתכנות מונחה עצמים יש לזהות תחילה את העצמים השותפים לפתרון‬
‫הבעיה‪ .‬העצמים הם הגורם המרכזי – בעזרתם מתבצעות פעולות – ולכן קוראים לסגנון תכנות זה‬
‫תכנות מונחה עצמים‪ .‬בדרך כלל בפתרון בעיה יש שימוש במספר עצמים בעלי אותם מאפיינים ולכן‬
‫מגדירים טיפוס‪ .‬טיפוס משמש תבנית ליצירת עצמים שלכל אחד מהם יש את אותן התכונות‪ ,‬ועל כל‬
‫אחד מהם ניתן להפעיל את אותן הפעולות‪ .‬אחרי אפיון הטיפוסים ניתן לפתח כל טיפוס כמחלקה‬
‫בשפת התכנות‪ .‬הפיתוח הוא מודולארי ומתייחס רק לממשק הטיפוסים האחרים‪ .‬כאשר טיפוס אחד‬
‫משתמש בטיפוס אחר‪ ,‬הדבר יכול לבוא לידי ביטוי בטיפוס של‪ :‬תכונות‪ ,‬פרמטרים‪ ,‬משתנים‬
‫מקומיים‪ ,‬או ערכים מוחזרים‪ .‬אין צורך בפעולה מיוחדת כדי להגיד שטיפוס אחד משתמש בטיפוס‬
‫אחר ומספיק שהוא מופיע באחד ההקשרים שפורטו‪ .‬על כל עצם מטיפוס‪ ,‬המופיע בטיפוס אחר ניתן‬
‫להפעיל את כל הפעולות המוגדרות בטיפוס שלו‪ .‬האלגוריתם הראשי לפתרון הבעיה ייכת ב במחלקה‬
‫ראשית‪ ,‬מחלקה שאינה מייצגת עצמים‪ ,‬אלא מנהלת את האלגוריתם לפתרון הבעיה הרצויה‪.‬‬
‫להלן מתכון לפתרון בעיה בתכנות מונחה עצמים‪:‬‬
‫(‪ )1‬זיהוי העצמים הנדרשים לפתרון הבעיה‪.‬‬
‫(‪ )2‬אפיון הטיפוסים של העצמים (טיפוסים המייצגים ישויות)‪.‬‬
‫(‪ )3‬פיתוח כל טיפוס בנפרד כמחלקה בשפת התכנות (תכונות‪ ,‬פעולות)‪.‬‬
‫(‪ )4‬פיתוח המחלקה הראשית ובה הפעולה הראשית שבה מופיע האלגוריתם הראשי לפתרון הבעיה‪.‬‬
‫כאשר בעיה מוצגת באופן מילולי בעברית‪ ,‬דרך אפשרית היא לנתח אותה מבחינה לשונית‬
‫במטרה לזהות את הישויות ואת הפעולות הנדרשות עבורם‪ .‬הזיהוי הלשוני הוא לפי הכללים‬
‫הבאים‪ :‬שמות עצם עשויים לציין עצמים (שיוכללו לטיפוסים) ופעלים עשויים לציין פעולות‪.‬‬
‫‪34‬‬
‫עיצוב תוכנה – טיפוס מורכב‬
‫©‬
‫כל הזכויות שמורות ל'מבט לחלונות'‬
‫כתוב מחלקה‬
‫תרגילים לטיפוס מורכב‪ :‬כתוב מחלקה‪...‬‬
‫שים ‪ :‬בכל מקרה בו יש לפתח מחלקה‪ ,‬הבסיס לפיתוח כולל‪ :‬הגדרת תכונות‪ ,‬הגדרת פעולות‬
‫בונות‪ ,‬והגדרת פעולות מאחזרות וקובעות לכל תכונה‪.‬‬
‫תרגיל ‪ 9‬רכבות ‪‬‬
‫הטיפוס קטר )‪ (Engine‬מאופיין על‪-‬ידי מספר רישוי ושנת יצור‪.‬‬
‫הטיפוס קרון‪-‬רכבת )‪ (Carriage‬מאופיין על‪-‬ידי מספר סידורי של הקרון‪ ,‬ומספר הנוסעים שיכולים‬
‫לנסוע בו‪ .‬הטיפוס רכבת )‪ (Train‬מאופיין על‪-‬ידי קטר ומערך של ‪ n‬קרונות‪ ,‬מספר הקרונות שיש‬
‫ברכבת בפועל ( ‪ n‬הוא מספר הקרונות המקסימלי שהרכבת יכולה להכיל)‬
‫א‪ .‬פתח מחלקה לכל אחד מהטיפוסים‪.‬‬
‫ב‪ .‬ממש את הפעולות החישוביות הבאות במחלקה רכבת‪:‬‬
‫‪ .1‬החלף את הקטר של הרכבת‪( .‬האם פעולה זו כבר הוגדרה לפני כן?)‬
‫‪ .2‬הוסף קרון לרכבת‪.‬‬
‫‪ .3‬החזר את מספר הנוסעים הכולל ברכבת‪.‬‬
‫‪ .4‬החזר את מספר הנוסעים הממוצע לקרון ברכבת‪.‬‬
‫ג‪ .‬פתח מחלקה ראשית הבונה רכבת‪ ,‬מפעילה את הפעולות שמימשת בסעיף ב ומציגה את נתוני הרכבת‪.‬‬
‫תרגיל ‪ :10‬הטיפוס משחק רובוטים ‪‬‬
‫פתח מחלקה משחק‪-‬רובוטים ‪ RobotGame‬שבה שתי תכונות‪ :‬מספר המשבצות בלוח המשחק ומערך‬
‫הרובוטים המשתתפים במשחק‪ .‬המחלקה תשתמש במחלקה ‪ Robot‬ותוגדרנה בה פעולות מתאימות‬
‫לניהול משחק הרובוטים כפי שתואר בספר יסודות‪ ,‬חלק ב בעמוד ‪ .146‬הרובוטים יכולים לנוע קדימה‬
‫או אחורה‪ .‬רובוט אשר חורג בצעדיו מגבולות לוח המשחק יוצא מן המשחק‪.‬‬
‫המאפיינים הבסיסיים של כל רובוט הם‪:‬‬
‫תכונות‪ :‬צבע‪ ,‬מספר משבצת עליו הוא עומד‪ ,‬האם נמצא במשחק?‪.‬‬
‫פעולות חישוביות‪ :‬צעד קדימה ‪ -‬הרובוט נע משבצת אחת קדימה‪ ,‬צעד אחורה ‪ -‬הרובוט נע‬
‫משבצת אחת לאחור‪ ,‬קפוץ קדימה ב‪ n -‬צעדים‪ ,‬קפוץ אחורה ב‪ n -‬צעדים‪.‬‬
‫על הפעולה הראשית לנהל בין הרובוטים משחק אקראי‪ .‬כללי המשחק הם‪ :‬הרובוטים מתחילים‬
‫‪ 4‬אפשרויות)‪ .‬אם‬
‫במשבצת מספר ‪ .10‬בכל שלב עבור כל רובוט מוגרלת פעולת ההתקדמות שלו (‬
‫הוגרלה פעולת קפיצה יש להגריל גם את ערך הקפיצה מ ‪ .1-6‬הרובוט הראשון שנעמד על המשבצת‬
‫‪ 100‬הוא המנצח‪ .‬אם רובוט מגיע למשבצת עליה נמצא רובוט אחר הוא מוציא את הרובוט השני מן‬
‫המשחק‪.‬‬
‫הגדר פעולה נוספת המחזירה את הרובוט הנמצא על משבצת שמספרה הוא הגדול ביותר‪ .‬פתח‬
‫מחלקה ראשית בה יוגדר עצם מטיפוס משחק‪-‬רובוטים‪ ,‬ותזומן הפעולה לניהול המשחק‪.‬‬
‫עיצוב תוכנה – טיפוס מורכב‬
‫©‬
‫כל הזכויות שמורות ל'מבט לחלונות'‬
‫‪35‬‬
‫תרגיל ‪ :11‬הטיפוס מרוץ מכוניות ‪‬‬
‫פתח מחלקה מרוץ‪-‬מכוניות ‪ CarRace‬שבה שתי תכונות‪ :‬מספר המכוניות המשתתפות במרוץ ומערך‬
‫המכוניות המשתתפות במרוץ‪ .‬המחלקה תשתמש במחלקה ‪( Car‬אפשר להוריד את המחלקה מאתר‬
‫האינטרנט באתר מלווה ספר בגאווה)‪ .‬ותוגדרנה בה פעולות מתאימות לניהול המרוץ כפי שתואר‬
‫בספר יסודות‪ ,‬חלק ב‪ ,‬תרגיל ‪ 3‬בעמוד ‪ :157‬עם פתיחת המרוץ כל המכוניות מזנקות בו זמנית‪ .‬במהלך‬
‫המרוץ המכונית מאטה או מאיצה לחלופין‪ .‬מדמה המרוץ שלנו יגריל עבור כל מכונית בכל שלב מספר‬
‫שלם בתחום של ‪ .1-4‬קוד ‪ – 1‬המכונית מגבירה מהירותה ב‪ 10 -‬קמ"ש (בתנאי שלא עברה את‬
‫המהירות המקסימלית שלה) ‪ ,‬קוד ‪ – 2‬המכונית מאטה את מהירותה ב‪ 10 -‬קמ"ש (בתנאי שלא ירדה‬
‫ממהירות ‪ 0‬קמ"ש)‪ ,‬קוד ‪ – 3‬המכונית מאטה את מהירותה ב‪ 20 -‬קמ"ש (בתנאי שלא ירדה ממהירות‬
‫‪ 0‬קמ"ש)‪ ,‬קוד ‪ – 4‬ארעה תקלה או התנגשות – המכונית פורשת מן המרוץ‪ .‬המכונית שחוצה ראשונה‬
‫את קו הסיום היא המנצחת במרוץ‪.‬‬
‫הגדר פעולה נוספת המחזירה את המכונית המובילה במרוץ‪ .‬פתח מחלקה ראשית בה יוגדר עצם‬
‫מטיפוס מרוץ‪-‬מכוניות‪ ,‬ותזומן הפעולה לניהול המרוץ‪.‬‬
‫הרחבה‪ :‬נניח שברצוננו לעקוב אחר התנהלות כל מכונית המשתתפת במרוץ לאורך המרוץ‪ .‬לצורך כך‬
‫יש לדעת בכל שלב כמה פעמים המכונית שינתה מהירות (האטה או האיצה)‪ .‬תכנן את השינויים‬
‫הנדרשים‪ .‬עבור כל תוספת שתאפשר את פתרון הבעיה המורחבת‪ ,‬שים דגש על זיהוי המחלקה‬
‫המתאימה להגדיר בה את התוספת‪.‬‬
‫‪‬‬
‫תרגיל ‪ :12‬חייל מילואים‬
‫א‪ .‬הגדר מחלקה תאריך )‪ *(MyDate‬שמאפייניה הם יום‪ ,‬חודש ושנה‪ ,‬המכילה פעולה בונה לפי‬
‫פרמטרים‪ ,‬פעולות קובעות‪ ,‬פעולות מאחזרות‪ ,‬ואת הפעולות החישוביות הבאות‪:‬‬
‫‪ .1‬פעולה המחזירה מחרוזת המתארת את התאריך ( ‪.(ToString‬‬
‫‪ .2‬פעולה המחזירה את היום העוקב ליום עליו מופעלת הפעולה‪.‬‬
‫‪ .3‬פעולה המחזירה את היום הקודם ליום עליו מופעלת הפעולה‪.‬‬
‫‪ .4‬פעולה המקבלת תאריך ומחזירה את ההפרש בימים בין התאריך עליו מופעלת הפעולה ובין‬
‫התאריך שהתקבל כפרמטר‪.‬‬
‫ב‪ .‬הטיפוס חייל מילואים )‪ (Soldier‬מאופיין על‪-‬ידי מספר אישי‪ ,‬דרגה‪ ,‬תאריך לידה‪ ,‬תאריך גיוס‬
‫לשרות סדיר ותאריך שחרור משרות סדיר‪ .‬בנה מחלקה המגדירה את תכונות הטיפוס‪ ,‬פעולה‬
‫בונה‪ ,‬פעולות קובעות‪ ,‬פעולות מאחזרות ואת הפעולה ‪ .ToString‬כמו‪-‬כן תכיל המחלקה פעולה‬
‫‪ true‬אם חייל מילואים צריך להשתחרר‬
‫בוליאנית המקבלת את התאריך של היום ומחזירה‬
‫ממילואים או לא‪ .‬חייל מילואים משתחרר כאשר הוא מגיע לגיל ‪.40‬‬
‫ג‪ .‬כתוב מחלקה ראשית הבונה בפעולה הראשית מערך של ‪ N‬חיילי מילואים ומזמנת את הפעולות‬
‫הסטטיות הבאות‪:‬‬
‫‪ )1‬פעולה המדפיסה לכל חייל מילואים את משך תקופת השרות הסדיר שלו בימים‪.‬‬
‫‪ )2‬פעולה המקבלת את התאריך של יום מסוים‪ ,‬מוציאה ממערך החיילים את חיילי המילואים‬
‫שצריכים להשתחרר‪ ,‬ומחזירה את מספר החיילים המעודכן שנשארו במערך‪ .‬יש להקפיד‬
‫שאברי המערך יופיעו במערך ברצף‪.‬‬
‫‪ )3‬פעולה המקבלת את מערך החיילים ואת מספר החיילים במערך ומדפיסה את פרטיהם‪.‬‬
‫‪36‬‬
‫עיצוב תוכנה – טיפוס מורכב‬
‫©‬
‫כל הזכויות שמורות ל'מבט לחלונות'‬
‫תרגיל ‪ :13‬תעודת זהות ‪‬‬
‫תעודת זהות של קטין מאופיינת על‪-‬ידי מספר תעודת‪-‬זהות‪ ,‬שם פרטי‪ ,‬שם משפחה‪ ,‬תאריך לידה‪,‬‬
‫ארץ לידה‪ ,‬ולאום‪ .‬תעודת זהות של מבוגר מאופיינת על‪-‬ידי מספר תעודת‪-‬זהות‪ ,‬שם פרטי‪ ,‬שם‬
‫משפחה‪ ,‬תאריך לידה‪ ,‬ארץ לידה ורשימת תעודות זהות של ילדיו הקטינים – עד ‪.15‬‬
‫א‪ .‬בנה מחלקות לייצוג הטיפוסים הדרושים‪ .‬חשוב‪ ,‬האם ניתן להשתמש באותו טיפוס עבור תעודת‬
‫זהות של קטין ועבור תעודת זהות של מבוגר? השתמש במחלקה המייצגת את הטיפוס‬
‫תאריך)‪ (MyDate‬אותה פיתחת בתרגיל ‪.14‬‬
‫ב‪ .‬הוסף את הפעולות הבאות למחלקות המתאימות‪ .‬ציין לכל פעולה לאיזו מחלקה היא שייכת‪ ,‬ותן‬
‫‪ .1‬הוסף‪-‬ילד‪-‬להורה‬
‫דוגמה לזימון הפעולה‪.‬‬
‫‪ .2‬הוצא‪-‬קטין‪-‬שהפך‪-‬מבוגר‪-‬מתעודת‪-‬הורה‪.‬‬
‫‪ .3‬החזר‪-‬מספר‪-‬ילדים‪-‬משותפים‪-‬לשני‪-‬מבוגרים‬
‫ג‪ .‬כתוב פעולה ראשית הבונה עצמים של ‪ 10‬קטינים‪ ,‬ומערך של ‪ 5‬מבוגרים‪ .‬הפעולה משייכת את‬
‫הקטינים להוריהם ומציגה כפלט את זוגות המבוגרים שיש להם ילדים משותפים‪ .‬כל זוג שיש לו‬
‫ילדים משותפים יופיע בפלט פעם אחת‪.‬‬
‫תרגיל ‪ :14‬בניינים ‪‬‬
‫חדר )‪ (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‬וכן‬
‫שמות בעלי דירות אלה‪.‬‬
‫עיצוב תוכנה – טיפוס מורכב‬
‫©‬
‫כל הזכויות שמורות ל'מבט לחלונות'‬
‫‪37‬‬
‫תרגיל ‪ :15‬מגדל של קוביות ‪‬‬
‫מגדל‪-‬של‪-‬‬
‫הטיפוס קובייה )‪ (Cube‬מאופיין על‪-‬ידי אורך צלע של קובייה וצבע הקובייה‪ .‬הטיפוס‬
‫קוביות )‪ (CubesTower‬מאופיין על‪-‬ידי מספר הקוביות המקסימלי שמגדל יכול להכיל‪ ,‬מספר‬
‫הקוביות שמגדל מסוים מכיל בפועל ואוסף הקוביות המונחות אחת‪-‬על השנייה‪.‬‬
‫על הטיפוס מגדל‪-‬של‪-‬קוביות )‪ (CubesTower‬מוגדרות הפעולות החישוביות הבאות‪:‬‬
‫‪ .1‬הוספת קובייה למגדל (אם המגדל אינו בתפוסתו המקסימלית)‪.‬‬
‫‪ .2‬הסרת קובייה מראש המגדל (אם יש במגדל לפחות קובייה אחת)‪.‬‬
‫‪ .3‬בדיקה האם צבע מסוים מופיע בקובייה במגדל‪.‬‬
‫‪ .4‬בדיקה האם המגדל ריק‪.‬‬
‫‪ .5‬בדיקה האם המגדל נמצא בתפוסתו המקסימלית‪.‬‬
‫א‪ .‬בנה מחלקה לטיפוס קובייה )‪ (Cube‬הכוללת את תכונות הקובייה‪ ,‬פעולה בונה‪ ,‬פעולות קובעות‪,‬‬
‫פעולות מאחזרות‪ ,‬פעולה המחזירה מחרוזת המתארת את הקובייה ( ‪ ,)ToString‬ואת הפעולה‬
‫‪ Equals‬המחזירה אמת אם שתי קוביות זהות‪ ,‬או שקר אחרת‪.‬‬
‫ב‪ .‬בנה מחלקה לטיפוס מגדל‪-‬של‪-‬קוביות )‪ (CubesTower‬הכוללת את תכונות המגדל‪ ,‬פעולה בונה‪,‬‬
‫פעולות מאחזרות‪ ,‬פעולות קובעות‪ ,ToString ,‬את הפעולה ‪ Equals‬המחזירה אמת אם שני‬
‫מגדלים זהים‪ ,‬או שקר אחרת ואת הפעולות החישוביות שפורטו לעיל‪.‬‬
‫ג‪ .‬בנה מחלקה ראשית המכילה פעולה ראשית הבונה מגדל‪-‬של‪-‬קוביות שגודלו המקסימלי מתקבל‬
‫‪ -1‬הוספת‬
‫כקלט‪ .‬הפעולה הראשית תקלוט מהמשתמש את הפעולה אותה הוא רוצה לבצע‪:‬‬
‫קובייה למגדל או ‪ -2‬הסרת קובייה מהמגדל‪ ,‬ותפעיל אותה על המגדל‪ .‬הקלט יסתיים כאשר ייקלט‬
‫מספר פעולה ‪ 0‬או כאשר לא ניתן לבצע פעולה מסוימת‪ .‬במקרה שלא ניתן לבצע פעולה מסוימת‬
‫יש להדפיס הודעה מתאימה‪ .‬לאחר כל פעולה יש להדפיס את המגדל‪.‬‬
‫ד‪ .‬מעוניינים להוסיף את הפעולה מגדל‪-‬צבעים‪-‬ייחודים‪ .‬הפעולה תבנה מגדל חדש ממגדל נתון‪.‬‬
‫במגדל החדש תופיע רק קובייה אחת מכל צבע שקיים במגדל הנתון‪ .‬בסוף הפעולה המגדל הנתון‬
‫יישאר ללא קוביות‪ .‬הפעולה תחזיר את המגדל החדש‪ .‬ממש את הפעולה בשני אופנים‪ :‬הראשון –‬
‫במחלקה מגדל‪-‬של‪-‬קוביות והשני – במחלקה הראשית‪ .‬כתוב זימון לכל אחת מהפעולות‪.‬‬
‫כתוב מחלקה‬
‫פרויקטים מסכמים בתכנות מונחה עצמים‬
‫תרגיל ‪ :16‬חניונים – תרגיל סיכום ‪I‬‬
‫‪‬‬
‫תכנה חדשנית לניהול חניונים דרך האינטרנט של חברת "חנה וסע" מאפשרת למנוייה להזמין מקום‬
‫חניה דרך האינטרנט לשעה מסוימת‪ ,‬תוך ציון משך הזמן המשוער‪ .‬ניתן להזמין מקומות חנייה רק‬
‫לאותו יום ובשעה עגולה‪ .‬בסופו של יום מתרוקנים כל החניונים‪ .‬אדם שמזמין חניה מקבל תשובה‬
‫המציינת אם ההזמנה ניתנת למימוש‪ .‬אם הזמנה אכן ניתנת למימוש – נשמר לאותו אדם מקום חנייה‬
‫מסוים בשעה הנדרשת‪ .‬מקום החניה נשמר ללקוח בשעה זו‪ ,‬כלומר הופך להיות מקום חניה תפוס‪.‬‬
‫במקרה שהמנוי הזמין מקום חניה ולא הגיע לחניון‪ ,‬המקום נשמר למשך שעה עבורה הוא מחויב‬
‫בתשלום‪ .‬במקרה שהמנוי מימש את הזמנתו – התשלום מתבצע בהתאם לזמן ההזמנה (ולא מזמן‬
‫‪38‬‬
‫עיצוב תוכנה – טיפוס מורכב‬
‫©‬
‫כל הזכויות שמורות ל'מבט לחלונות'‬
‫ההגעה)‪ .‬למימוש מערכת זו מוגדרים הטיפוסים‪ :‬כתובת‪ ,‬מנוי‪ ,‬הזמנה‪ ,‬חניון‪ ,‬מערכת חניונים‪.‬‬
‫להלן דיאגרמת תרשים לכל אחד מהטיפוסים‪ .‬הנח כי לכל אחד מהטיפוסים קיימות פעולות בונות‪,‬‬
‫קובעות מאחזרות והפעולה ‪.ToString‬‬
‫הטיפוס‬
‫הטיפוס‬
‫תכונות‬
‫כתובת‬
‫רחוב מטיפוס מחרוזת‬
‫מספר מטיפוס שלם‬
‫מטיפוס מחרוזת‬
‫עיר‬
‫תכונות‬
‫מטיפוס מחרוזת‬
‫שם‬
‫מטיפוס מחרוזת‬
‫ת‪.‬ז‪.‬‬
‫כתובת מטיפוס כתובת‬
‫סכום‪-‬לתשלום מטיפוס ממשי‬
‫פעולות‬
‫הוסף‪-‬תשלום(סכום‪-‬תשלום)‬
‫ביצוע‪-‬תשלום‬
‫הטיפוס‬
‫הזמנה‬
‫הטיפוס‬
‫תכונות‬
‫מספר‪-‬הזמנה מטיפוס שלם‬
‫מנוי מטיפוס מנוי‬
‫מספר‪-‬רכב מטיפוס מחרוזת‬
‫מספר‪-‬חניון מטיפוס שלם‬
‫שעת‪-‬התחלה‪-‬משוערת מטיפוס שלם‬
‫מטיפוס שלם‬
‫שעת‪-‬סיום‪-‬משוערת‬
‫שעת‪-‬סיום מטיפוס ממשי‬
‫מקום‪ -‬חניה מטיפוס שלם‬
‫סטטוס‪-‬ביצוע מטיפוס בוליאני‬
‫פעולות‬
‫בצע‪-‬הזמנה()‬
‫החזר‪-‬סכום‪-‬לתשלום‪-‬עבור‪-‬הזמנה()‬
‫הטיפוס‬
‫מנוי‬
‫חניון‬
‫תכונות‬
‫כתובת מטיפוס מחרוזת‬
‫מטיפוס מחרוזת‬
‫ת‪.‬ז‪.‬‬
‫רשימת הזמנות מטיפוס מערך של הזמנה‬
‫מערך‪-‬מקומות‪-‬חניה מטיפוס מערך בוליאני‬
‫תעריף‪-‬שעת‪-‬חניה מטיפוס ממשי‬
‫פעולות‬
‫האם‪-‬הזמנה‪-‬ניתנת למימוש(מספר‪-‬הזמנה)‬
‫הוסף‪-‬הזמנה(הזמנה)‬
‫עדכן‪-‬מקומות‪-‬חניה‪-‬להזמנות (שעה‪-‬נוכחית)‬
‫(שעה‪-‬נוכחית)‬
‫בטל‪-‬הזמנות‪-‬שלא‪-‬מומשו‬
‫שחרור‪-‬רכב (מספר‪-‬רכב‪ ,‬שעה‪-‬נוכחית)‬
‫החזר‪-‬סכום‪-‬לתשלום‪-‬עבור‪-‬חניה(מספר‪-‬הזמנה)‬
‫מערכת חניונים‬
‫תכונות‬
‫מערך‪-‬מנויים‬
‫מספר‪-‬מנויים‬
‫מערך‪-‬חניונים‬
‫פעולות‬
‫הוסף‪-‬מנוי (מנוי)‬
‫מחק‪-‬מנוי(מנוי)‬
‫האם‪-‬מנוי‪-‬קיים(מנוי)‬
‫מטיפוס מערך של מנוי‬
‫מטיפוס שלם‬
‫מטיפוס מערך של חניון‬
‫א‪.‬‬
‫ממש את הפעולה בצע‪-‬הזמנה() שבמחלקה הזמנה‪ .‬הפעולה מתבצעת כאשר רכב מגיע לחניון‪.‬‬
‫הפעולה מעדכנת את סטאטוס הביצוע של ההזמנה ל‪ . true -‬כתוב הוראת זימון לפעולה וציין‬
‫מאיזו מחלקה יתבצע זימון זה‪.‬‬
‫ממש את הפעולה עדכן‪-‬מקומות‪-‬חניה‪-‬להזמנות(שעה‪-‬נוכחית) שבמחלקה חניון‪ .‬הפעולה מעדכנת‬
‫את מקומות החניה שהוזמנו לשעה‪-‬נוכחית זו להיות תפוסים‪ .‬כתוב הוראת זימון לפעולה וציין‬
‫מאיזו מחלקה יתבצע זימון זה‪.‬‬
‫ג‪.‬‬
‫ממש את הפעולה שחרור‪-‬רכב שבמחלקה חניון‪ .‬הפעולה מעדכנת את מקום החניה של הרכב‬
‫להיות פנוי‪ ,‬מעדכנת את שעת הסיום‪ ,‬ומוסיפה למנוי את הסכום לתשלום‪.‬‬
‫ב‪.‬‬
‫עיצוב תוכנה – טיפוס מורכב‬
‫©‬
‫כל הזכויות שמורות ל'מבט לחלונות'‬
‫‪39‬‬
‫ממש את הפעולה בטל‪-‬הזמנות‪-‬שלא‪-‬מומשו(_שעה‪-‬נוכחית) שבמחלקה חניון‪ .‬הפעולה בודקת אלו‬
‫הזמנות לא מומשו (אלה פעולות שעברה שעה מזמן ההתחלה המשוער ועדיין לא הגיעו)‪ .‬הפעולה‬
‫מפעילה על מכוניות שהזמנותיהן לא מומשו את הפעולה שחרור‪-‬רכב(מספר_רכב‪_ ,‬שעת_יציאה)‪.‬‬
‫במחלקה הראשית מוגדרת הפעולה קליטת‪-‬הזמנות‪ .‬להלן אלגוריתם כללי לביצוע הליך זה‪:‬‬
‫ד‪.‬‬
‫ה‪.‬‬
‫קליטת‪-‬הזמנות(_מערכת_חניונים)‬
‫כל עוד יש הזמנות בצע‪:‬‬
‫ קלוט מספר ת‪.‬ז‪ .‬של מנוי‪ .‬אם המנוי לא קיים במאגר המנויים בנה עצם מטיפוס מנוי והוסף‬‫אותו למאגר המנויים‪.‬‬
‫ קלוט את פרטי ההזמנה ההתחלתיים‪ :‬מספר‪-‬רכב‪ ,‬שעת‪-‬התחלה‪-‬משוערת‪ ,‬שעת‪-‬סיום‪-‬‬‫משוערת ומספר חניון‪ .‬אם לא ידוע מספר החניון‪ ,‬קלוט כתובת מבוקשת והפעל את הפעולה‬
‫החזר‪-‬מספר‪-‬חניון‪-‬הקרוב‪-‬ביותר‪-‬לכתובת(_כתובת) הנמצאת בטיפוס מערכת‪-‬חניונים‪.‬‬
‫ בנה עצם מטיפוס הזמנה‪ .‬אם ההזמנה ניתנת למימוש הוסף אותה לרשימת ההזמנות של‬‫החניון‪ .‬הדפס הודעה מתאימה אם ההזמנה ניתנת למימוש או לא‪.‬‬
‫ממש פעולה זו ב‪ C#-‬וכן את הפעולות הדרושות כפי שפורטו לעיל‪.‬‬
‫ו‪ .‬הוסף למחלקה הראשית פעולה המדפיסה לכל חניון את מספר המקומות הפנויים‪.‬‬
‫תרגיל ‪ :17‬טלפון סלולרי – תרגיל סיכום ‪ II‬‬
‫‪60‬‬
‫מאפייני טלפון סלולארי הם‪ :‬מספר הטלפון‪ ,‬שם בעל הטלפון‪ ,‬תעודת זהות של בעל הטלפון‪,‬‬
‫שיחות נכנסות אחרונות‪ 60 ,‬שיחות יוצאות אחרונות‪ 60 ,‬הודעות נכנסות אחרונות‪ 60 ,‬הודעות יוצאות‬
‫אחרונות‪ ,‬וספר טלפונים בגודל של ‪ 200‬מספרים‪.‬‬
‫שיחה נכנסת מאופיינת על‪-‬ידי‪ :‬תאריך‪ ,‬שעה‪ ,‬מספר הטלפון ממנו התקבלה השיחה‪.‬‬
‫שיחה יוצאת מאופיינת על‪-‬ידי‪ :‬תאריך‪ ,‬שעה‪ ,‬מספר הטלפון אליו הופנתה השיחה‪.‬‬
‫הודעה נכנסת מאופיינת על‪-‬ידי‪ :‬תאריך‪ ,‬שעה‪ ,‬מספר הטלפון ממנו התקבלה ההודעה ותוכן ההודעה‪.‬‬
‫הודעה יוצאת מאופיינת על‪-‬ידי‪ :‬תאריך‪ ,‬שעה‪ ,‬מספר הטלפון אליו נשלחה ההודעה ותוכן ההודעה‪.‬‬
‫איש קשר בספר טלפונים מאופיין על‪-‬ידי‪ :‬שם‪ ,‬מספר טלפון‪ ,‬וקטגוריה ( בית‪/‬נייד‪/‬אחר)‪.‬‬
‫במחלקה הראשית יש פעולה ראשית הבונה מערך של ‪ 50‬טלפונים סלולאריים‪ .‬כמו‪-‬כן הפעולה קולטת‬
‫את מספר הפעולה המבוקשת )‪ ,(1-4‬מפעילה אותה‪ ,‬ומעדכנת את תכונות המכשירים בהתאם‪ .‬הנח כי‬
‫הפעולות מתבצעות בין שני טלפונים הנמצאים במערך‪.‬‬
‫הפעולות האפשריות הן ‪ )1 :‬חייג‪-‬למספר‪-‬טלפון‪ )2 ,‬קבל‪-‬שיחת‪-‬טלפון‪ )3 ,‬שלח‪-‬הודעה‪ )4 ,‬קבל‪-‬הודעה‪.‬‬
‫א‪.‬‬
‫ב‪.‬‬
‫ג‪.‬‬
‫ד‪.‬‬
‫ה‪.‬‬
‫רשום תרשימי ‪ UML‬לכל אחד מהטיפוסים הדרושים ‪ .‬חשוב על אפיון יעיל‪.‬‬
‫בנה מחלקה לכל אחד מהטיפוסים‪.‬‬
‫בנה מחלקה ראשית ובה פעולה ראשית המבצעת את המשימות שפורטו בשאלה‪.‬‬
‫הוסף פעולה בוליאנית המקבלת ‪ 2‬טלפונים סלולאריים ובודקת האם הייתה התקשרות כלשהי‬
‫בין שני הטלפונים‪ .‬ציין לאיזו מחלקה יש להוסיף פעולה זו‪.‬‬
‫הפעל מהפעולה הראשית את הפעולה שכתבת בסעיף ד עבור כל שני טלפונים הנמצאים במערך‬
‫הטלפונים‪ ,‬והצג כפלט עבור כל זוג את מספרי הטלפון‪ ,‬ואת הערך המוחזר מהפעולה‪.‬‬
‫‪40‬‬
‫עיצוב תוכנה – טיפוס מורכב‬
‫©‬
‫כל הזכויות שמורות ל'מבט לחלונות'‬
‫‪ ‬טיפוס מורכב (‪ – )Composed class‬טיפוס המוגדר על ידי המשתמש שחלק מן התכונות שלו הן‬
‫מטיפוס שאינו בסיסי בשפה אשר הוגדר על ידי המשתמש או שהוא כלול בספריות של השפה‪.‬‬
‫ העקרונות והיתרונות של תכנות מונחה עצמים באים לידי ביטוי כאשר יש שילוב ושימוש במספר‬‫טיפוסים כמו למשל בדוגמה של השילוב בין הטיפוסים‪ :‬תלמיד‪ ,‬מורה‪ ,‬כיתה‪ ,‬ביה"ס‪.‬‬
‫‪ ‬כללי הפיתוח של טיפוס מורכב הם בדיוק כמו כללי הפיתוח של כל טיפוס‪:‬‬
‫‪‬‬
‫‪‬‬
‫‪‬‬
‫‪‬‬
‫הגדרת תכונות שחלקן מטיפוסים לא בסיסיים שהוגדר על‪-‬ידי המשתמש או נמצאים‬
‫בספריות השפה‪.‬‬
‫פעולה בונה ‪ -‬אם פעולה בונה מקבלת את ערכי התכונות כפרמטרים‪ ,‬יש ליצור קודם את‬
‫העצמים המהווים ערכים לתכונות בעצם המורכב שנבנה‪ ,‬ולשלוח אותם כפרמטרים‬
‫המתאימים לפעולה הבונה של העצם המורכב‪.‬‬
‫פעולות מאחזרות – לכל תכונה תוגדר פעולה מאחזרת כך גם לתכונות שהטיפוס שלהן אינו‬
‫בסיסי‪ .‬במקרים אלה יוחזר עצם שהוא ערך התכונה‪.‬‬
‫פעולות קובעות ‪ -‬לכל תכונה תוגדר פעולה קובעת‪ ,‬כך גם לתכונות שהטיפוס שלהן הוגדר על‪-‬‬
‫ידי המשתמש‪ .‬במקרים אלה תקבל הפעולה עצם שהוא הערך החדש של התכונה‪.‬‬
‫‪ ‬מערך של עצמים‬
‫שימוש במערך של עצמים יכול להיות כמשתנה בפעולה וגם כתכונה של טיפוס חדש‪ .‬אין הבדל‬
‫אם מערך העצמים משמש כמשתנה מקומי (בפעולה הראשית או בכל פעולה אחרת) או כתכונה‬
‫של עצם‪.‬‬
‫למרות עקרון זה יש הבדלים הניכרים במרכיבים הבאים‪:‬‬
‫(‪ )1‬בדרך הפנייה אל משתנה או אל תכונה (פנייה ישירה‪ ,‬או פנייה אל העצם שזו התכונה שלו)‪.‬‬
‫(‪ )2‬בדרך הגדרת הפעולות – פעולות סטטיות יקבלו את המערך כפרמטר‪ ,‬פעולות המוגדרות‬
‫בטיפוס המייצג ישות לא יהיו סטטיות‪ ,‬וגם לא יקבלו את המערך כפרמטר‪ .‬פעולות אלו יופעלו על‬
‫עצם שהמערך הוא אחת התכונות שלו ולכן אין צורך בפרמטר‪.‬‬
‫‪ ‬שלבים בפתרון בעיה בתכנות מונחה עצמים‪:‬‬
‫‪‬‬
‫‪‬‬
‫‪‬‬
‫‪‬‬
‫זיהוי העצמים הנדרשים לפתרון הבעיה‪.‬‬
‫אפיון הטיפוסים של העצמים (טיפוסים המייצגים ישויות)‪.‬‬
‫פיתוח כל טיפוס בנפרד (תכונות‪ ,‬פעולות)‪.‬‬
‫פיתוח המחלקה הראשית ובה הפעולה הראשית שבה מופיע האלגוריתם הראשי לפתרון‬
‫הבעיה‪ .‬לשרות הפעולה הראשית יכולות להיות מוגדרות גם פעולות סטטיות אחרות‬
‫במחלקה הראשית‪.‬‬
‫עיצוב תוכנה – טיפוס מורכב‬
‫©‬
‫כל הזכויות שמורות ל'מבט לחלונות'‬
‫‪41‬‬