ABA


"צריך עזרה חשובה בג'נריקס בג'אווה"
גירסת הדפסה        
קבוצות דיון פיתוח, תיכנות ובניית אתרים נושא #15943 מנהל    סגן המנהל    מפקח   Winner    צל"ש   מומחה  
אשכול מספר 15943
gilme

   20:59   11.06.10   
אל הפורום  
  צריך עזרה חשובה בג'נריקס בג'אווה  
 
   אני כותב תוכנית קטנה שיש בה שרת - ServerSocket
ואני מממש בעצמי פרוטוקול להתקשרות בין השרת לקליינט שיתחבר אליו.

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

כמוכן קיים לי קלאס חיבור" (Session) שהוא Thread שמייצג חיבור ספציפי אחד בין קליינט לשרת, כמובן לכל חיבור יש Socket משלו.
אני רוצה שכל Session ידע ליצור לעצמו אובייקטים מסוג Message
לכל הודעה שתתקבל, ואלה יטפלו בביצוע לפי אופי ההודעה.

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

צירפתי קובץ עם הקוד הרלוונטי והודעות השגיאה.
https://rotter.name/User_files/nor/4c1279426997d939.doc
משהו עם הגנריקה לא עובד, או עם זה ששמתי קלאס פנימי אבסטרקטי אולי.

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


                                שתף        
מכתב זה והנלווה אליו, על אחריות ועל דעת הכותב בלבד

  האשכול     מחבר     תאריך כתיבה     מספר  
  מכתב Deuce  11.06.10 22:27 1
     תודה.. דבר נוסף.. gilme 12.06.10 02:27 2
         את האמת לא. Deuce  12.06.10 03:51 3
             ........ gilme 13.06.10 01:47 4
                 כן, זה בהחלט אפשרי. Deuce  13.06.10 02:09 5
  אני לא מת על שימוש בInner Classes akoka2 13.06.10 17:02 6
     הפתרון שלך לא נכון קונספטואלית. Deuce  13.06.10 17:38 7
         אני מסכים איתך חלקית, akoka2 13.06.10 19:11 8
     יש את זה גם בC#.. ronen333  14.06.10 14:28 9
         נחמד לראות שיש התייחסות רצינית (: gilme 14.06.10 14:52 10
         הייתה לי שיחה די מרתקת עם אייל על הנושא, akoka2 14.06.10 17:57 11

       
Deuce 
חבר מתאריך 1.9.08
6225 הודעות
   22:27   11.06.10   
אל הפורום  
  1. מכתב  
בתגובה להודעה מספר 0
 
השגיאות יחסית מוזרות ולא שכיחות.
אני חושב שיש לך בעייה של עיצוב תוכנה קודם כל.

יש לך INNER CLASS של MESSAGE ואז אתה גם יורש רק מה-INNER CLASS? וגם ב-OUTER CLASS אתה מקבל כקלט extends ל-MESSAGE. זה לא נכון מבחינה קונספטואלית, אל תעשה את MESSAGE כ-INNER CLASS, זה הכל. אתה לא יכול לעשות NESTED CLASS שנמצא ביחסים עם המחלקה העוטפת, לרשת אותו מהצד ולצפות שכל ההיררכיה עם המחלקה העוטפת עדיין תתקיים.

יתר על כן, אני לא מבין למה בחרת שזה יהיה NESTED CLASS. בד"כ אתה בוחר משהו להיות NESTED אם קודם כל אתה לא מצפה מהמחלקה הפנימית ליותר מידי שינויים. במידה וכן, תן לה חופש.

מה שאני אומר לסיכום:
תעשה CLASS של MESSAGE בנפרד. במחלקה Session תיצור מופע פנימי של המחלקה MESSAGE וזהו.







                                                         (ניהול: מחק תגובה)
מכתב זה והנלווה אליו, על אחריות ועל דעת הכותב בלבד
gilme

   02:27   12.06.10   
אל הפורום  
  2. תודה.. דבר נוסף..  
בתגובה להודעה מספר 1
 
   יש קורלציה בין Session ל-Message בזה שכל אובייקט שיורש מ-Message
חייב גישה לשדות רבים ב-Session שיצר את אותו אובייקט מסוג Message.

אני לא רוצה להגדיר getters שהם public כי זה פוגע לי ב-encaps.

להעביר ב-constructor כ-6 מצביעים, לא נשמע לי אלגנטי (זה הרבה נתונים).

יש דרך אחרת שאתה יכול אולי להציע לכך? או פשוט ללכת על constructor?


                                                         (ניהול: מחק תגובה)
מכתב זה והנלווה אליו, על אחריות ועל דעת הכותב בלבד
Deuce 
חבר מתאריך 1.9.08
6225 הודעות
   03:51   12.06.10   
אל הפורום  
  3. את האמת לא.  
בתגובה להודעה מספר 2
 
ערכתי לאחרונה בתאריך 12.06.10 בשעה 16:32 בברכה, Deuce
 
הניסיון לערבב בין INNERR CLASS להורשה הוא פגום מיסודו.
אם תאפשר ל-INNER CLASS גישה להכל ותאפשר לאובייקט שיורש ממנו גם כן גישה לכל השדות הפרטיים אז פגעת באופן דרסטי בהורשה.

הפשרה היא:
א. תעשה INNER CLASS שיכול לגשת פשוט לכל מה שהוא צריך ולא תירש ממנו (כלומר הוא FINAL ברמה מסויימת), שזה בסדר, תלי במטרות.
ב. אין שום דבר רע בלהעביר 6 מצביעים, פשרה יכולה להיות ע"י כך שתעביר 6 משתנים; בכל מקרה לא רע להעביר 6 מצביעים, זה לא סוף העולם.

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

עריכה:
אני אוסיף עוד קצת מידע.
קודם כל, אתה יכול להעביר רשומה, כלומר לבנות class final שפשוט מייצג את המידע שאתה רוצה להעביר בקונסטרקטור.
דבר שני, אני לא נכנסתי לך לפרטים בקוד אבל בד"כ מחלקה של MESSAGE לא צריכה להיות בקשר כה הדוק עם המחלקה המקורית. היא רק מדפיסה הודעות. ואם היא כן, אז תעשה אותה כ-NESTED CLASS ואל תירש ממנה.






                                                         (ניהול: מחק תגובה)
מכתב זה והנלווה אליו, על אחריות ועל דעת הכותב בלבד
gilme

   01:47   13.06.10   
אל הפורום  
  4. ........  
בתגובה להודעה מספר 3
 
   אצלי המחלקה האבסטרקטית Message תפקידה להיות "אב"
לכל אותן הודעות אפשריות שייתקבלו עפ"י הפרוטוקול.

מכאן - אני מעביר להן את הטיפול מלא בכל "בעיה".
אם לדוגמה התקבלה הודעת hello, האובייקט המתאים מסוג Message
יטפל בכל נושא ה-handshake- כל האישורים שצריכים להתבצע בזמן
ההיכרות והחיבור בין הצדדים.
מכאן שהוא משתמש ב-Streams של אותו Socket רלוונטי,
ואף ניגש למבני נתונים רלוונטים (לא משנה בדיוק למה..).


מקווה שהבנת יותר לאן חתרתי..

עזרת לי עם רעיון או שניים.

תודה..

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


                                                         (ניהול: מחק תגובה)
מכתב זה והנלווה אליו, על אחריות ועל דעת הכותב בלבד
Deuce 
חבר מתאריך 1.9.08
6225 הודעות
   02:09   13.06.10   
אל הפורום  
  5. כן, זה בהחלט אפשרי.  
בתגובה להודעה מספר 4
 
אני באופן אישי לא הייתי מאציל כל כך הרבה סמכויות ל-MESSAGE כי תפקידה להציג הודעות. ז"א, אם אתה נותן לו לטפל בכל העסק של ה-handshake אז אתה מאציל לו סמכות יחסית כבדה. אני כמובן לא רואה את התמונה הגדולה, אבל בעקרון MESSAGE אמור להציג הודעה.

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






                                                         (ניהול: מחק תגובה)
מכתב זה והנלווה אליו, על אחריות ועל דעת הכותב בלבד
akoka2

   17:02   13.06.10   
אל הפורום  
  6. אני לא מת על שימוש בInner Classes  
בתגובה להודעה מספר 0
 
   לדעתי זה לא אלגנטי, זה סוג של פיצ'ר הזוי של JAVA לא ראיתי את זה ביותר מדי שפות.

אם הבנתי אותך נכון אז Message לא צריכה ליהיות מחלקה פנימית, היא צריכה לעשות extend לאובייקט שבעצם מכיל את כול נתוני החיבור (Thread), אז מה הבעיה אז מה הבעיה לבצע הורשה מThread ולהשתמש בMessage בתור הMain Instance שלך, מעבר לזה, אם ההנחה היא שתיהיה יותר מהודעה אחת פר חיבור, אז אתה צריך קלאס שבעצם יכיל בתוכו Collection של הודעות.

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


                                                         (ניהול: מחק תגובה)
מכתב זה והנלווה אליו, על אחריות ועל דעת הכותב בלבד
Deuce 
חבר מתאריך 1.9.08
6225 הודעות
   17:38   13.06.10   
אל הפורום  
  7. הפתרון שלך לא נכון קונספטואלית.  
בתגובה להודעה מספר 6
 
אתה לא יורש ממחלקה כדי להשתמש סתם במידע שלה, אתה יורש ממחלקה כאשר מתקיים יחס מסויים. בד"כ היחס הוא is a. הודעה היא לא Session, ולכן איך שלא תסתכל על זה, זה רע מאוד אם Message תירש ממנה או מכל אובייקט שמכיל נתוני חיבור. היא יכולה להשתמש ב-instance של נתוני החיבור, אבל בשום פנים ואופן לא לרשת ממנו. ואני אומר את זה בטון נחרץ לגמרי, זה אמנם פותר את הבעייה הטכנית אבל מחריב את כל העקרונות של OOP.

לגבי nested/inner classes - זכותך לא לאהוב את זה, אם כי אני חושב שמדובר בכלי מאוד נחמד. הוא עונה על הצורך ב-JAVA הרבה פעמים שאתה רוצה להשתמש ב-struct פנימי. מכיוון שאין ב-JAVA רשומות, אז אפשר תמיד לעשות INNER CLASS שייצג את ה-CLASS וזה אחלה. כדרך אגב מחלקות פנימיות קיימות גם ב-C++ ובפיתון.






                                                         (ניהול: מחק תגובה)
מכתב זה והנלווה אליו, על אחריות ועל דעת הכותב בלבד
akoka2

   19:11   13.06.10   
אל הפורום  
  8. אני מסכים איתך חלקית,  
בתגובה להודעה מספר 7
 
   אני יכול להגיד שInner Class מחריב את עקרונות הOOP בדיוק כמו שההורשה שדיברתי עליה מחריבה.

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

חוץ מזה יש קשר בין Session לMessages החיבור עצמו מכיל מידע על משתמש אחד או יותר, שהSession של החיבור שלו שייך ישירות לכול הודעה והודעה, וככה גם כול הודעה יודעת לאן היא צריכה להגיע.

עכשיו לגבי הInner Class של Message בתוך Session זה באמת לדעתי פתרון שהוא לא נכון עיצובית, תכנונית, וכול פרמטר שמשתייך לארכיטקטורה של תוכנה, אני בטוח שיש פתרון יפה יותר, אולי אפילו ליצור מחלקה נוספת שתאחד את כול האובייקטים, משהו כמו Registry שדרכו הוא יוכל לגשת לכול האובייקטים ולאתחל אותם, שוב אולי הInner Class יעבוד מעולה, אבל אני לא בעדו בכלל.


                                                         (ניהול: מחק תגובה)
מכתב זה והנלווה אליו, על אחריות ועל דעת הכותב בלבד
ronen333 
חבר מתאריך 20.2.03
6069 הודעות
   14:28   14.06.10   
אל הפורום  
  9. יש את זה גם בC#..  
בתגובה להודעה מספר 6
 
   ולכל דבר יש את המטרות שלו.


                                                         (ניהול: מחק תגובה)
מכתב זה והנלווה אליו, על אחריות ועל דעת הכותב בלבד
gilme

   14:52   14.06.10   
אל הפורום  
  10. נחמד לראות שיש התייחסות רצינית (:  
בתגובה להודעה מספר 9
 
   אני חושב שאני אלך על "לתת לכל Message את המושכות" -
לתת מצביעים ל-input stream ול-output stream כך שכל הודעה
תבצע את הפעולה שלה מול הצד השני.

יכול להיות ששווה להשתמש ב-Executor?
לא הבנתי בדיוק מה היתרון שלו, אבל אם לצורך העניין יש לי הודעה
אחת שצריכה לדעת לעשות עבודה של כמה הודעות נוספות (מן הודעה מרכזית
שיודעת לבצע כמה פעולות שבפועל אפשר לבקש מכמה הודעות נפרדות
לבצע בנפרד - אחת אחרי השניה) -
האם הכלי של Future הוא הפיתרון?
הבנתי ש-Thread שמממש את Callable יכול להחזיר Future כמשימה עתידית
שיש לבצע, כך שאותה הודעה מרכזית יכול להחזיר ל-Executor - ה"מנהל"
מטלות - לבצע פעולות נוספות של הודעות אחרות.
* אני מדבר פה על Executor שעובד בצורה של תור, לא מבצע משימות בו-זמנית.

כמוכן, לא מספיק ברור לי האם ל-Executor יש יתרון כ"מנהל" על פני סתם יצירה של Threads והרצתם ע"י start() ?
מהגדרתם כ- Threads הם אכן ירוצו במקביל..
אם לדוגמה אני צריך לספק שירות uploads, האם לא מספיק לפתוח thread
חדש לכל העלאה (ע"י האזנה, יצירת סוקט ויצירת thread), ולשמור אותם במבנה נתונים כלשהו?

תודה!! מצטער על החפירה!!


                                                         (ניהול: מחק תגובה)
מכתב זה והנלווה אליו, על אחריות ועל דעת הכותב בלבד
akoka2

   17:57   14.06.10   
אל הפורום  
  11. הייתה לי שיחה די מרתקת עם אייל על הנושא,  
בתגובה להודעה מספר 9
 
   והבנתי יותר את החשיבה שלו לגבי זה, כרגע אני עדיין חושב שהשימוש בזה הוא מאוד מאוד בלתי תלוי בעקרונות הבסיסיים של תכנות מונחה עצמים, זה Feature שיכול להיות מאוד נחמד אם אתה מתכנן מערכות שלא אמורות להיות ג'נריות מראשיתן, מעבר לזה, אני בעד דברים יותר מופשטים, כמו מחלקה שתעשה implementation למנשק, או הורשה ממחלקה אבסטרקטית אחרת, אני בטוח שגם אייל יסכים איתי שזה הרבה יותר אלגנטי, מעבר לכך, יש משהו לא אלגנטי במחלקה שמכילה מחלקה אחרת אף על פי שעקרונות השימוש בזה ברורים לי מאוד עכשיו.


                                                         (ניהול: מחק תגובה)
מכתב זה והנלווה אליו, על אחריות ועל דעת הכותב בלבד

תגובה מהירה  למכתב מספר: 
 
___________________________________________________________________

___________________________________________________________________
למנהלים:  נעל | תייק בארכיון | מחק | העבר לפורום אחר | מחק תגובות | עגן אשכול
       



© כל הזכויות שמורות ל-רוטר.נט בע"מ rotter.net