פרק לדוגמה - מבט לחלונות
Transcription
פרק לדוגמה - מבט לחלונות
פרק 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 עיצוב תוכנה – טיפוס מורכב © כל הזכויות שמורות ל'מבט לחלונות'