» נושאי לימוד
» נושאי לימוד
יום שני 29 באפריל 2024
תוכנית דוגמא
דף ראשי  מתקדמים  וקטורים, Hashtables ורשימות  תוכנית דוגמא גרסה להדפסה

תוכנית דוגמא

תוכנית זו לא נועדה להשיג דבר מה מועיל מלבד הדגמה של הדרך לשימוש במחלקות וקטור

ו- hashtable, ובממשק רישום.

 

בנוסף, היא מדגימה מושגי תכנות חשובים אחרים ב- Java כגון רישום רשימה של אובייקטים עבור מטרה מסוימת, עיבוד כל האובייקטים ברשימת האובייקטים שנרשמו, עבודה ברמת האובייקט הכללי והשלכה למטה במקרה הצורך וכ"ו.

 

התוכנית ארוכה למדי ומורכבת במידה מה, כך שנתקדם בצעדים קטנים.

 

חלקי קוד מעניינים

התרחיש הוא להלן. התוכנית מספקת את היכולת לאתחל אובייקטים המתארים אנשים בו לכל אובייקט יש שם, גיל, ומשקל. התוכנית מספקת בנוסף את היכולת להשוות בין שני אובייקטים שכאלה על בסיס גיל או משקל על מנת לקבוע מיהו הפחות מביניהם.

 

משתמשים במחלקת בקרה על מנת לבחון את התוכנית. פונקצית main() של מחלקת הבקרה מאתחלת חלק מהאובייקטים המכילים שמות, גילאים ומשקל של מספר אנשים.

 

פונקצית main של מחלקת הבקרה גם מאתחלת אובייקט אשר מתפקד כמנהל עבור השוואת אובייקטים אלה בזוגות על מנת לדווח מי הוא צעיר יותר וקל יותר.

 

פונקציה בשם registerPair() של מחלקת CompareManager נקראת על מנת לרשום שלוש זוגות של אובייקטים עבור השוואה בשלב מאוחר יותר.

 

פעולות אלה מוצגות בחלק הקוד הבא.

 

  public static void main(String[] args){
    //Instantiate a manager to handle the comparisons
    CompareManager compareManager = new CompareManager();
    
    //Register three pairs of data objects with the
    // manager
    compareManager.registerPair(new Data("Tom",65,180),
                                 new Data("Dick",60,170));
    compareManager.registerPair(new Data("Harry",40,160),
                                 new Data("Dick",60,170));
    compareManager.registerPair(new Data("Harry",40,160),
                                  new Data("Tom",65,180));

 

 

 

 

 

 

 

 

 

 

 

 

 

שים לב שאובייקטים אלה מוכנסים כאובייקטים אנונימיים, על אף שאין דרישה לכך בתוכנית זו.

 

המנהל יוצר רשימה של זוגות אובייקטים שכאלה כפי שהם נרשמים, וכאשר מתבקש לעשות זאת, משווה ומדווח על כל הזוגות המוכלים ברשימת הנרשמים.
(למעשה, על מנת לפשט את הדברים, המנהל סוגר כל זוג בתוך אובייקט ורושם אובייקט זה).

 

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

 

רשימת הנרשמים מתרחשת בסוגים שונים של פעולות ב-Java למשל טיפול באירועים, שליטת מראה מודל  תוך שימוש ב-  Observable, וכו.'

 

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

 

כאשר מחלקת הבקרה מבקשת מהמנהל לבצע את ההשוואות על כל האובייקטים ברשימת האובייקטים, הבקשה נעשית על פי השוואה בין גיל או משקל. מחלקה בשם CompareHow  מוגדרת למטרה בלעדית של הגדרת הקבועים הסימבוליים של גיל ומשקל. מחלקה זו מגדירה בנוסף קבוע סימבולי עבור חוסר תקפות (INVALID) בו משתמשים לוודא שהתוכנה עובדת כמצופה כאשר בקשה נוצרת להשוואה על בסיס לא חוקי.

 

חלק הקוד הבא מראה את פונקצית main() במחלקת הבקרה אשר מבקשת מאובייקט מנהל ההשוואה להשוות בין כל זוגות האובייקטים הרשומים ולדווח על התוצאות. שים לב ששלוש קריאות ל- compareAll() מתבצעות, אחת עבור כל קבוע סימבולי.

 

    compareManager.compareAll(CompareHow.AGE);
    compareManager.compareAll(CompareHow.WEIGHT);
    compareManager.compareAll(CompareHow.INVALID);

 

וכל זאת מתרחש בפונקצית main() של מחלקת הבקרה.

 

ישנה הגדרת מחלקה קטנה בשם נתונים - Data. משתמשים במחלקה זו על מנת לסגור את נתוני שם, גיל, ומשקל עבור אדם באובייקט. הקוד עבור מחלקה זו הוא פשוט מדי מכדי שנציגו בחלק זה. תוכל לראותו ברישום   תוכנית מלא לקראת סוף השיעור.

 

כמו כן, כפי שצוין קודם, ישנה הגדרת מחלקה קטנה עבור מחלקה בשם CompareHow אשר מטרתה הבלעדית היא להגדיר קבועי מחרוזת סימבוליים עבור גיל, משקל ואי חוקיות. בקבועים סימבוליים אלה נשתמש מאוחר יותר כמפתחות ב- hashtable. שוב, מחלקה זו היא פשוטה מדי להצגה בחלק זה.

 

ממשק בשם Comparable מוגדר אשר מכריז על פונקציה בשם copmarePair(). פונקציה זו מיושמת במספר מחלקות שונות בתוכנית.

 

interface Comparable{
  public void comparePair(String how, Object obj1,
                                             Object obj2);
}//end Comparable interface

 

לכן, מושג נוסף מודגם בתוכנית זו בהגדרה ובשימוש בממשקים שהוגדרו על ידי המשתמש.

 

שים לב שההגדרה לממשק Comparable הינה גם מקום טוב להגדרת הקבועים הסימבוליים שצוינו לעיל מכיוון שהגדרת קבועים מורשית בממשק.

 

מחלקת המנהל (אשר מאותחלת על ידי ומתקשרת עם מחלקת הבקרה) נקראת CompareManager. משתמשים במחלקה זו על מנת:

·   להחזיק ברשימה של זוגות אובייקטים רשומים ואז

·  לנהל את ההשוואה הממשית ביו זוגות אובייקטים ברשימת הזוגות הרשומים.

מחלקה זו משתמשת באובייקט ממחלקה בשם CompateTool על מנת לבצע את ההשוואות כאשר מגיע זמן השוואת האובייקטים. האובייקט ממחלקת CompateTool מבצע דברים מסובכים יחסית תוך שימוש באובייקט Hashtable.

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

חלק הקוד הבא מראה את תחילת ההגדרה למחלקת CompareManager בה מוכרזים משתני האובייקטים עבור פוינטרים לאובייקט CompareTool ואובייקט וקטור. שים לב שפוינטר לאובייקט CompareTool מוחזק על ידי סוג אובייקט כללי.

 

 

class CompareManager{
  Object compareTool;
  Vector myListOfObjects;


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

במחלקה פנימית משתמשים למטרה זו כפי שנראה בחלק הבא. למרות שזוהי מחלקה פשוטה מאד, העובדה שזוהי מחלקה פנימית קרוב לוודאי הופכת אותה לראויה להצגה ודיון בחלק זה.
 
  class PairOfObj{
    Object obj1;
    Object obj2;
    
    PairOfObj(Object obj1,Object obj2){//constructor
      this.obj1 = obj1;
      this.obj2 = obj2;
    }//end constructor
  }//end inner-class PairOfObj


הבנאי עבור אובייקט compareManager (מוצג להלן) מאתחל אובייקט CompareTool בשם compareTool ואובייקט וקטור בשם myListOfObjects לשימוש כפי שהוגדר לעיל.

  CompareManager(){//constructor for a manager object
    this.compareTool = new CompareTool();
    myListOfObjects = new Vector();
  }//end constructor

 

מחלקת CompareManager מכילה פונקציה בשם registerPair() אשר נקראת מבחוץ על מנת לרשום זוג אובייקטים להשוואה בשלב מאוחר יותר. פונקציה זו סוגרת פוינטרים לשני אובייקטים נכנסים בתוך אובייקט יחיד ואז קוראת לפונקצית addElement() על אובייקט הוקטור ליצירת רשימה של אובייקטים.

לא נעשו הכנות להסרת אובייקטים מהרשימה של אובייקטים רשומים. זהו לעיתים קרובות המצב כאשר משתמשים ברשימה להחזיק ברשימת אובייקטים רשומים. מן הסתם, הדבר לא יהיה קשה עקב הפונקציות הקיימות באובייקט הוקטור. בנוסף, פונקצית רישום אינה עושה מאמץ כלשהו על מנת למנוע העתקת אובייקטים ברשימה, דבר שנעשה לעיתים.

 

  public void registerPair(Object obj1,Object obj2) {
    this.myListOfObjects.addElement(
                                 new PairOfObj(obj1,obj2));
  }//end registerPair

 

 

מחלקת CompareManager מכילה בנוסף פונקציה בשם CompareAll() אשר נקראת על מנת להשוות ולדווח על כל האובייקטים ברשימת האובייקטים הרשומים. פונקציה זו בעלת פרמטר מחרוזת יחיד אשר נועד להיות אחד הקבועים הסימבוליים שהוגדרו קודם לכן אשר מגדיר איך ההשוואה נעשית (גיל או משקל).

פונקצית compareAll() קוראת לפונקצית elements()  על אובייקט הוקטור אשר מאתחל ומחזיר אובייקט המיישם את ממשק הרישום. במילים אחרות, היא מחזירה אובייקט רישום.
על בסיס הדיון הקודם, עליך להיות מודע מהו אובייקט רישום, ומה ניתן לעשות אתו.

משתמשים בפונקציות ממשק הרישום על מנת להוציא את כל האובייקטים המורכבים מרשימת האובייקטים. מוציאים את כל אחד מהאובייקטים בזוג מהאובייקט המורכב הרשום ומעבירים אותו,
יחד עם פרמטר מחרוזת המגדיר איך לערוך את ההשוואה, לפונקציה בשם
comparePair().
זוהי פונקציה של אובייקט
CompareTool שתואר קודם. שים לב ש- comparePair() מוכרזת בממשק Comparable ויש להגדיר את כל המחלקות המיישמות ממשק זה.

 

  public void compareAll(String how){
    Enumeration myEnum = myListOfObjects.elements();
    
    while(myEnum.hasMoreElements()){
      Object aPairOfObj = myEnum.nextElement();
      ((Comparable)compareTool).comparePair(how,
                             ((PairOfObj)aPairOfObj).obj1,
                             ((PairOfObj)aPairOfObj).obj2);
    }//end while loop
  }//end compareAll
}//end CompareManager class

 

 

 

 

 

 

 

 

 

 

 

 

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

זהו סוף פונקצית compareAll()  וסוף מחלקת compareManager.

כעת נדון במחלקת CompareTool ממנה אובייקט מאותחל על מנת לבצע את ההשוואה בין האובייקטים.

זה מעט מסובך, כך שעלייך להקדיש תשומת לב רבה.

 

מחלקה זו מכילה שתי מחלקות פנימיות בשם AgeCompare ו WeightCompare. כל אחת ממחלקות אלו מיישמת את ממשק Comparable, ולכן מגדירה פונקציה בשם comparePair().

אולם, פונקצית ה- comparePair() היא שונה בין שתי המחלקות.
במקרה אחד, הקוד עוצב על מנת להשוות בין שני אובייקטים על בסיס משתנה אובייקט בשם גיל. במקרה השני, הפונקציה נועדה להשוות בין אובייקטים על בסיס משתנה לאובייקט בשם משקל.

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

חלק הקוד הבא מראה את תחילת מחלקת CompareTool ואת ההכרזה על פוינטר למשתנה של אובייקט hashtable, יחד עם אתחול  האובייקט.

 

חלק קוד זה גם מראה את אחת המחלקות הפנימיות בשם AgeCompare בה דנו לעיל.
שתי המחלקות הפנימיות הן דומות מאד, כך שרק אחת מוצגת כאן.
תוכל לעיין בשניה ברישום תוכנית המלא לקראת סוף השיעור.

שים לב שמחלקות פנימיות אלה מגדירות פונקציה בעלת אותו השם, comparePair(), כמו הפונקציה במחלקות ההורה. בנוסף שים לב שבשלושת המקרים הפונקציה מיישמת את ממשק Comparable. אולם, היישום בשלושת המקרים הוא שונה, תלוי במחלקה המוגדרת ובצרכים של האובייקטים במחלקה. הקוד להשוואה ממשית היא פשוטה ברגע שתעבור את דרישות ההשלכה מטה.

class CompareTool implements Comparable{
  private Hashtable myHashTable = new Hashtable();
  //_____________________________________________________//

  private class AgeCompare implements Comparable {
    public void comparePair(String how,Object obj1,
                                             Object obj2){
      System.out.println("In AgeCompare method");
      Data temp1 = (Data)obj1;//Cast incoming objects to
      Data temp2 = (Data)obj2;// the correct type.
      //Make the comparison on age
      if(temp1.age<temp2.age)
        System.out.println(temp1.name + 
                         " is younger than " + temp2.name);
      else System.out.println(temp1.name + 
                     " is not younger than " + temp2.name);
    }//end trace()
  }//end inner-class AgeCompare

 

כאן הדברים מסתבכים במקצת, אזי שים לב -
הבנאי עבור מחלקת
CompareTool מאתחל אובייקט במחלקת hashtable ומאחסן (שם) שני אובייקטים בתוך ה-Hashtable יחד עם ערכי המקשים המתאימים.

אובייקט אחד המאוחסן ב- hashtable הוא פוינטר לאובייקט מסוג AgeCompare יחד עם המפתח לערך גיל.
האובייקט השני המאוחסן ב- hashtable הוא פוינטר לאובייקט מסוג WeightCompare  יחד עם המפתח לערך המשקל.

וודא כי אתה מבין ששני אובייקטים אלה מאותחלים ממחלקה פנימית כפי שתואר לעיל, ומהן ההשלכות מכך.

 

  public CompareTool(){//constructor
    myHashTable.put( CompareHow.AGE, new AgeCompare() );
    myHashTable.put( CompareHow.WEIGHT, 
                                     new WeightCompare() );
  }//end constructor 

 

ברגע שאובייקט ה- CompareTool נבנה, הוא מכיל אובייקט hashtable מיוחד במינו. על ידי קריאה לפונקצית get() על אובייקט ה-hashtable, העברת אחד משני המפתחות כפרמטר, יש אפשרות להשיג פוינטר לאובייקט אשר מכיל פונקצית אובייקט שנועד לבצע השוואה בין שני אובייקטים על בסיס גיל או משקל. לפונקציה זו ניתן לקרוא על מנת לבצע את ההשוואה הממשית.

לכן, התוכנית מדגימה את השימוש באובייקט hashtable על מנת לאחסן ולהחזיר פוינטרים לאובייקטים המכילים פונקציות אובייקט שימושיות בניגוד לערכי נתונים פשוטים) על בסיס של ערך מפתח.

(מושג זה יתכן ונראה לך זר מאד בנקודה זו, אך נשתמש רבות במושג כאשר נחקור את השימוש בפונקצית invoke() על מחלקת פןנקציה בהשתקפות API סביב שיעור 262).

מחלקת CompareTool מיישמת את ממשק Comparable כלומר היא גם מגדירה את הפונקציה בשם comparePair(). זוהי הפונקציה הנקראת על ידי האובייקטים של מחלקת CompareManager על מנת להשוות בין שני אובייקטים. בנוסף לפוינטרים לשני האובייקטים שיעברו השוואה, פונקציה זו גם מקבלת פרמטר מחרוזת המציין איך לערוך את ההשוואה: גיל או משקל.

אך, פונקציה זו אינה מבצעת את ההשוואה. במקום זאת, היא בודקת על מנת לוודא שקבוע המחרוזת הנכנס מכיל מפתח ל- hashtable. אם זהו ערך מפתח תקף, היא קוראת לפונקצית get() כפרמטר, ומחזירה פוינטר לאובייקט המקושר למפתח זה. הפוינטר לאובייקט מכיל פונקציה בעל אותו השם, comparePair(). פונקצית comparePair() של הפוינטר לאובייקט נקראת על מנת לבצע את ההשוואה הממשית.

לכן, על ידי שימוש בערך המפתח הנכנס על מנת לגשת לאובייקט hashtable, פונקציה זו משיגה גישה לפונקציה אחרת אשר נועדה לערוך את ההשוואה בדרך המתאימה לערך המפתח.

זהו מושג מעניין של בחירה. במקרה של תוכנית פשוטה, רק שתי פונקציות שונות מיוצגות על ידי אובייקטים ב- hashtable. אבל, יתכנו עשרות, מאות או אף אלפי פונקציות שונות המיוצגות על ידי אובייקטים ב- hashtable, ובחירה ביניהן תתכן על בסיס ערך מפתח הקשור לכל אחד מהן.
זוהי גישה שנעה מעבר ל-
if else או switch case.

שים לב שכאשר פונקציה זו בשם comparePair() מעוררת את פונקצית comparePair(),
היא מעוררת פונקציה המוגדרת באחד האובייקטים המאוחסנים ב-
hashtable. היא לא מבצעת קריאה חוזרת לעצמה.

 

  public void comparePair(String how, Object obj1,
                                              Object obj2){
    if(myHashTable.containsKey(how)){
      Object theMethod = myHashTable.get(how);
      ((Comparable)theMethod).comparePair(how,obj1,obj2 );
    }//end if
    else System.out.println(
                "Invalid Key, could throw exception here");
  }//end comparePair()

 

על אף ויתכן שזו אינה הדרך הפשוטה להשיג זאת, היא אכן מדגימה את השימוש באובייקט hashtable בדרך מעניינת למדי. במיוחד, אובייקט ה- hashtable אינו מכיל נתוני ערכים פשוטים, הוא מכיל פוינטרים לאובייקטים אשר בתורם מכילים פונקציות מעניינות. פונקציות אלא ניתנות לבחירה על בסיס ערכי מקש.

כפי שצוין קודם, נעשה שימוש נרחב במושג כאשר נשתמש בפונקצית invoke() של מחלקת פונקציה בהשתקפות API על מנת ליצור מתאמי אירוע חכמים בחלק המתקדם של ההדרכה סביב שיעור 262.

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

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

ו- hashtable יחד עם ממשק רישום, ובנוסף הדגמה של חלק מהמושגים החשובים כגון יצירה והחזקה ברשימה של אובייקטים רשומים, בהשלכה מטה מאובייקט כללי לסוג אמיתי, וכו'.
היא גם נועדה להכין אותך להבנה של הדברים בהם תתקל בחלק המתקדם של ההוראה ביחס להשתקפות
API.

הפלט מהתוכנית מוכלת בהערות בתחילת רישום התוכנית.

 02-12-03 / 20:05  עודכן ,  13-10-03 / 19:11  נוצר ע"י רונית רייכמן  בתאריך 
 מחלקת וקטור + מחלקת Hashtable - הקודםהבא - רישום תוכנית 
תגובות הקוראים    תגובות  -  0
דרכונט
מהי מערכת הדרכונט?
אינך מחובר, להתחברות:
דוא"ל
ססמא
נושאי לימוד
חיפוש  |  לא פועל
משלנו  |  לא פועל
גולשים מקוונים: 12