סוגיה בעיצוב OO

ייוניי

New member
סוגיה בעיצוב OO

התחלתי לעשות לאחרונה סוג מסויים של refactoring שלא מצאתי תעוד לגביו בשום מקום ואני תוהה על טיבו. אני אקרא לו - "Replace Subtyping with Abstract Factory". העניין הוא שיש לי ממשק כללי וממשק נוסף שנראה שהוא מכיל את הממשק הכללי. דוגמא:
public interface Printable { void print(Printer toThisPrinter); } public interface Document { void openIn(Editor editor); }​
עכשיו אני רוצה להגדיר שכל מסמך הוא גם ניתן להדפסה. דרך אחת לעשות זאת היא להוסיף מתודת print גם למסמך (וביישום אפשר לעבוד עם Printable ואפשר גם לא), אבל אז אני קצת מאבד את ה reuse במתודת ה print משום שאני לא יכול להתייחס למסמך כ Printable בשום הקשר. הדרך השני היא ליצור קשר של הורשה בין Document ל Printable. על פניו הכל טוב ויפה - כל יישום של Document חייב ליישם Printable ואני יכול להתייחס אליו בהתאם. אבל, מה עם הממשקים היו גדולים יותר? ומה עם בנוסף ל Printable המסמך שלי הוא גם Browseable וכו'... אני מגיע למצב של ממשק גדול מדי שצריך ליישם בכל מחלקה. אז הפתרון שחשבתי עליו הוא להחליף את הורשת הממשקים ב Abstract Factory באופן הבא:
public interface Document { void openIn(Editor editor); Printable getPrintable(); }​
מה הרווחתי? עכשיו אני יכול לבחור בכל יישום של Document בין 3 אפשרויות: 1. ליישם גם את Printable ולהחזיר this במתודת getPrintable. 2. ליישם את Printable כ Inner Class (שאולי לא חייב לממש את כולו אלא לרשת מ AbstractPrintable כלשהוא) ולהחזיר אותו. 3. לאתחל אובייקט אחר שמיישם Printable ולהחזיר אותו. אז יש לי יותר גמישות ואני גם חוסך קוד ובפוטנציה יש לי פחות מחלקות לערוך כשאעשה שינויים בממשק Printable. (קשה קצת לראות את זה בדוגמא הפשטנית אבל צריך לדמיין שיש ל Printable יותר מתודות...). מצד שני, העברת מתודות בין ממשק אחד לשני נעשית קשה יותר. אשמח לשמוע אם מישהו התמודד עם סוגיה זו והאם יש השלכות בעייתיות שאני מפספס במודל הזה. או לחילופין אם מדובר ב refactoring מוכר ומתועד שפשוט לא הצלחתי למצוא...
 

צונאמי

New member
עצות מסוכנות מחסר ניסיון ../images/Emo8.gif

(מצורפת גם דיאגרמה) יהיו את האובייקטים הבאים: Printer,Browser,document. האובייקטים printer, browser יחשפו את הממשק הדרוש להם כדי להדפיס אובייקט כלשהו. האובייקט document יצטרך לחשוף בממשק שלו פונקציונאליות שתאפשר לתשאל את המסמך כדי להדפיס/להציג אותו. (כרגע לא חייב להיות מותאם לממשק שהגדירו printer ו-browser) - מן הסתם יהיה ממשק לערוך את המסמך, אז שיהיה גם ממשק לקרא את המסמך בצורה דומה. עכשיו לחלק האומנותי: (זה עדיין ניסיוני - בתהליכי מחשבה) עבור כל doc נכתוב מחלקה ג'נרית שמקבל את ה-DOC הקונקרטי כפרמטר וותבצע ADAPT (משתמש בפונקציונאליות הקיימת של DOC כדי להתאים אותו ל-printer browser הדרוש) לפי הממשק שה-printer/browser חשף.(המחלקה יורשת את הממשק) * שים לב איך ההפשטות המרכזיות Printer,Browser,document לא "ניפגמות" והחלק הקונקרטי נדחק ל-ADAPTER. * דרך אגב השימוש הוא ב-TEMPLATE כדי לאפשר שימוש חוזר עבור מסמכים שחושפים את אותו הממשק. (משפחה של מסמכים) (עבור מסמכים אחרים שחושפים פונקציונליות דרושה אבל לא ממשק נצטרך לכתוב ADAPTER נוסף)
 

ייוניי

New member
אמנם אני חובב גדול של Adaptor-ים

אבל הפתרון שלך חורג לי מה use case... אם היה לי design שבו Document חושף מתודות שקשורות להדפסה וספציפיות אליו (וזה בהחלט יכול להגיע בעתיד אבל לא כרגע) הייתי בהחלט יוצר adaptor ועושה decoupling מושלם בין Printable ל Document. אבל, במקרה שלי אין צורך בהוספת מתודות הדפסה לממשק של Document וכל מה שאני רוצה ממנו זה שיהיה Printable בצורה זו או אחרת. כך שהפתרון שאתה מציע דורש ממני לעבוד יותר קשה בכל מחלקה שתיישם את Document וזה קצת בזבוז.
 

צונאמי

New member
תגובה

קודם כל אני הייתי אומר שמסמך חושף מתודות שמאפשרות לתשאל אותו.(להדפיס זה משהו קונקרטי מידי - ומכאן צומחות להן מחלקות מפלצתיות) * מסמך לא מדפיס את עצמו, מדפסת מדפיסה מסמך. איך לעבוד קשה יותר ? אם ה-ADAPTER הוא TEMPLATE ויש לך משפחה של מסמכים שחושפים את אותו הממשק אז אתה צריך לכתוב רק פעם אחת ADAPTER.
 

ייוניי

New member
--->

יש כאן כמה דברים שאני לא מסכים איתך לגביהם: 1. "שמסמך חושף מתודות שמאפשרות לתשאל אותו" - מתודות מיועדות לביצוע התנהגות ולא לתשאול. כל הרעיון של Data Abstraction הוא לא "לבקש" מאובייקט לעולם מידע לביצוע פעולה אלא פשוט לומר לו לבצע אותה. אילו מתודות אתה מציע שמסמך יחשוף לטובת התשאול הזה? הרי מה שאני מנסה להשיג בדוגמא שהצגתי הוא מסמך אבסטקרטי שאני לא יודע מה המבנה שלו אבל אני יודע שהוא יכול להיות מודפס. (Word, Excel, HTML...) 2. "מסמך לא מדפיס את עצמו, מדפסת מדפיסה מסמך" - מדפסת כותבת סימנים על דפים בהתאם לפקודות שניתנות לה, אין לה שום מושג מה זה "מסמך" או איך להדפיס אותו. וטוב שכך, כי כשאני אשנה מחר לחלוטין את המבנה של מסמך מסויים אני מניח שארצה לשנות את הפקודות שהוא שולח למדפסת כשמדפיסים אותו אבל ממש לא בא לי לגעת במחלקות שרלוונטיות למדפסת. 3. "איך לעבוד קשה יותר?" - זה נכון שאני צריך לכתוב את ה Adapter פעם אחת אבל בשיטה שהצעת אני אמור לממש עבור כל Document הרבה יותר מתודות משתכננתי, וגם להתאים כל מימוש לממשק קשיח יותר ממה שתכננתי. מבחינתי זו עבודה קשה יותר מאשר לממש מתודת print פשוטה אחת...
 

צונאמי

New member
==>> ../images/Emo67.gif

2. קודם כל שהתכוונתי מדפסת לא התכוונתי למכשיר אלה למושג האבסטרקטי של משהו שמדפיס - יכולה להיות גם מדפסת למסך. אולי יותר נכון לקרא לזה writer מהמדפסת - WRITER- יודעת לקחת מידע בפורמט כלשהו(בילבלתי עם מסמך) ולהציג אותו. עם זה אתה מסכים ? 1+3. נראה לי שאתה צודק בקשר לתשאול במקרה הזה. אבל עדיין יש לי בעיה עם זה שמסמך מבצע לעצמו PRINT. אולי מסמך ידע להמיר את עצמו לפורמט הרצוי עבור ה-WRITER? (כאשר פורמט רצוי לא בהכרח אומר STRING יכול להיות מבנה נתונים כלשהו) משהו בדומה למנגנון serialize. דרך אגב כבר ציינתי שניסיון אין לי - ככה שאני דוחף את האף למטרות לימוד !
מקווה שלא אכפת לך.
 

ייוניי

New member
-->

כולנו כאן למטרות לימוד, ממש ממש לא אכפת לי.ראה, קראתי למדפסת שלי Printer מסיבה מסויימת והיא שמדובר בממשק להדפסה. Writer זה שם קצת כללי מדי לדעתי. הדפסה ל Print Preview למסך בהחלט נכללת תחת Printer בעיני אבל גם בעיני רוב אוכלוסיית המפתחים וחלק מאוכלוסיית המשתמשים - כך שאני חושב שהמונח Printer הוא אבסטרקטי מספיק בשביל להכיל סוגי מדפסות שונים וספציפי מספיק בשביל להבין למה זה משמש. אני גם מעדיף שמדפסת תדע לבצע פקודות הדפסה ולא לקבל מידע בפורמט כלשהו. התהליך של נירמול מידע פנימי של אובייקט לפורמט שאובייקט אחר יודע לעשות איתו משהו הוא תהליך ארוך ומייגע ומסבך מדי את הפיתוח. קח את HTML לדוגמא, תחשוב כמה שנים לוקח לבנות תשתית שתאפשר לכתוב אפליקציות ל WEB בצורה נוחה ועדיין נתקלים לפעמים בבעיות של HTML שמיוצא לא נכון... בהשוואה ל Windows API למשל (שעובד עם פקודות ולא עם פורמט מידע) זה לקח הרבה יותר זמן ומאמץ, למרות שבמקרה הזה זה היה שווה את זה. לכן אגב, אנחנו משתדלים ב OOP להעביר "מסרים" פשוטים בין אובייקטים ולא מבני נתונים גדולים - זה עושה את התקשורת להרבה יותר פשוטה.מנגנון selialization הוא בד"כ הרבה יותר כוללני ו"דורסני" בגלל היותו היבט טכני יותר של המערכת ולא עיצובי - וגם בו שים לב שאין מנגנון תשאול אלא כל אובייקט יודע לסרייל את עצמו ולדה-סרייל את עצמו בלי לחשוף מבני נתונים. (אלא אם אתה משתמש במנגנון של reflection אבל אז אתה כבר לגמרי מחוץ ל Object Model...) לגבי הבעיה שלך עם זה שהמסמך יודע לעשות print אני מציע לך לחשוב על זה ככה, כדי למזער קוד ולעשות אותו יעיל יותר אתה צריך לשאוף לכמה שפחות קריאות למתודות. עכשיו קח לדוגמא את הקוד הבא:
void method(Printer printer, Document document) { // Print the document }​
כדי לבצע את ההדפסה במינימום קוד אני צריך לבחור בין שתי אפשרויות: או לקרוא ל print על ה document ולשלוח את printer או לקרוא ל print על ה Printer ולשלוח את document. האופציה הנוספת של לבקש מ Document מידע בפורמט מסויים ואז לשלוח אותו ל printer זו כבר קריאת מתודה מבוזבזת. עכשיו, כבר הסכמנו שאין הגיון שמדפסת תכיר בקיומו של מסמך כי זה הרבה מעבר להבנתה - אז מה שנשאר זה לקרוא ל print על המסמך...
 

צונאמי

New member
../images/Emo27.gif

איזה פקודות הדפסה למשל יש למדפסת? (אף פעם לא לא התעסקתי עם זה - אבל היה נראה לי שהיא מקבלת STREAM של קודים ופשוט מדפיסה אותם) ה-PRINT שלך בכל מקרה יצטרך להמיר את עצמו לפקודות מדפסת.(שקול לנירמול מידע פנימי לא?) אז אני חשבתי שכל אובייקט שאתה רוצה להדפיס אותו יהיה לו CONVERTOR ל-STREAM - יהיה לו מידע על מבנה פנימי של טיפוס. (הכוונה שהCONVERTOR עצמו יהיה ה-STREAM) ואז ה-CONVERTOR יקבל מצביע למסמך שצריך להדפיס (הוא עדיין לא יעשה כלום, רק ישמור את המצביע - זה חלק מימוש מוסתר ולכן נוכל גם לשנות שימיר אותו באותו רגע, לא קריטי) ל-CONVERTOR ממשק של STREAM ולכן אובייקט מדפסת יוכל לקרא ממנו (מדפסת מכירה STREAM) בקשר ליעילות אז לא נראה לי שזה ISSUE - אתה תמיד יכול להשתמש ב-INLINE כדי "לצמצם" קריאות לשגרות קטנות. מזה מנגנון REFLECTION ? זה setters/getters? אהה וכן כבר הסכמתי שתשאול זה לא רעיון כל כך מדהים
. (ואני יודע פחות או יותר איך מנגנון selialization עובד)
 

ייוניי

New member
-->

מדפסת אכן מקבלת כל מיני קודים אבל אני ממש לא מתכוון להתעסק עם זה באפליקציה שלי. יש לי תשתית להדפסה שאני מקבל ממערכת ההפעלה (או מ NET Framework. במקרה שלי) אשר עוזרת לי להדפיס. הרי לכל מדפסת יש סטנדרטים משלה ואני משאיר את עניין התרגום למערכת ההפעלה... הפקודות שאני מדבר עליהם הם PrintText, PrintImage, DrawLine דברים כאלה. בקשר ליעילות אני לא מדבר על ביצועים אלא על תחזוקה. יותר קל לי לתחזק תהליכים כשיש לי פחות קוד. ולגבי inlining זה לא רלוונטי ל interface call (או לכל virtual call למעשה) אז זה לא יעזור לי גם מהבחינה הזו. reflection זה מנגנון מעולם ה interpreted languages - מוכר בעיקר בהקשר של Java ו NET. ועוסק בניתוח וביצוע פעולות על מבנה פנימי של אובייקט בזמן ריצה. לא בדיוק getters/setters.
 

צונאמי

New member
כמה שאלות קטנות ...

לפי התיכנון שלך, איך תיראה המתודה PRINT של DOC ? היא תקבל את מדפסת כפרמטר ?
 

ייוניי

New member
משהו כזה

public class NewsDocument : Document, Printable { string _title; string _body; System.DateTime _time; public NewsDocument(string title, string body, System.DateTime time) { // init fields } public void openIn(Editor editor) { // implementation } public void print(Printer printer) { printer.printText(0, 0, _title); printer.printText(0, 400, string.Format("{0}", _time)); printer.printLine(20, 0, 20, 600); printer.printText(30, 0, _body); } public Printable getPrintable() { return this; } }​
זה מאוד סכימטי כמובן... הרעיון הוא שיש לי גמישות רבה לגבי אופן ההדפסה.
 

צונאמי

New member
תקן אותי אם אני טועה אבל ...

זה דומה קצת למנגנון SERALIZE. במקום STREAM אתה מעביר PRINTER. ובמקום לכתוב ל-STREAM אתה כותב ל-PRINTER.
 

ייוניי

New member
בקוד הפשטני שלי

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

orenphp

New member
לדעתי, אין מה להסתבך.

הייתי עושה משהו בסגנון:
public interface IPrintable { string GetDataForPrinter(); } public class Document : IPrintable { public string GetDataForPrinter() { // build the wanted string for the printer to print. } } public class Printer { public static void Print(IPrintable toPrint) { // do print on toPrint.GetDataForPrinter(); } } public class Tester { public void TestIt() { Document d = new Document(); // fill the document with the required data. Printer.Print(d); } }​
שני דברים: 1. תנסה לקרוא לשמות של הinterface-ים שלך עם I כתחילית (סטנדרט של MS), הרבה יותר קל ככה לראות/לתחזק במעבר (עם העיניים) על מחלקה מסוימת. 2. יתכן וGetDataForPrinter צריך להחזיר אולי איזה אובייקט שיקבע את הסטנדרט הדרוש בשביל הדפסה, ולא סתם איזה סטרינג פשוט. מה דעתך ?
 

ייוניי

New member
הרגת לי את ה polymorphism...

קודם כל הפכת לי את Document למחלקה כשרציתי ממשק. כלומר, רציתי להגדיר ממשק כללי למסמכים שונים ולא לכתוב מימוש של מסמך ספציפי. מה שהיה חשוב לי זה שכל מחלקה שתממש את Document תצטרך לספק גם ממשק Printable בצורה זו או אחרת. תחשוב על זה שיש לי כבר מחלקה שמחזיקה מערך של אובייקטים מסוג Document ובהתאם לבקשה היא יכולה לפתוח מסמך לעריכה (על ידי מתודת ה openIn של Document), ובנוסף יש לי מחלקה קיימת שמקבלת Printable ומכינה תהליך הדפסה (מציגה תיבת דו-שיח לבחירת מדפסת וכו'...). אני רוצה להיות יכול להעביר לה ממשק Printable עבור מסמך מסויים. אבל Document זו לא מחלקה! יש כמה סוגים שונים של מסמכים והם ממומשים במחלקות שונות. אחר כך גם הפכת את Printer למחלקה ושמת לה פונקציה סטטית. אבל יש לי סוגי מדפסות שונות עם התנהגות שונה ואני לא רוצה להיות תקוע עם קריאה סטטית... לגבי אובייקט שייקבע סטנדרט להדפסה כתבתי רבות על כך בשרשור עם "צונאמי" אבל אני פשוט רואה בזה בזבוז קוד. בהחלט יכול להיות שכל מה ש Document.print יעשה זה (Printer.PrintImage(System.Drawing.Image image וגם אם הוא יכיל יותר פקודות זה עדיין בזבוז להתחיל ליצור פורמט מיוחד ולכתוב interpreter עבורו ב Printer וכו'... לגבי תחיליות אני בניגוד למיקרוסופט כותב הרבה יותר interface-ים כך שמבחינת intellisense ה I התחילית לא משתלמת. אני יותר אוהב את השיטה של סיומת Impl למחלקות למרות שגם זה מעצבן לפעמים.
 

orenphp

New member
תראה...

נראה כאילו גיבשת איזו דעה בנושא ואתה לא רוצה לזוז ממנה, וזה לגיטימי במידה והכל סגור מבחינתך. במידה ולא, אל תשלול מה שאני מציע, תנסה להבין למה אני חותר. היה לי ר"צ בצבא שאהב את עיקרון הSIMPLE, לפעמים זה היה קצת מצחיק אותי, אבל זה בהחלט עזר לי להבין דבר או שתיים בנוגע לעיצוב. אתה חייב בסופו של דבר לכתוב קוד שיהיה נוח לתחזוקה אבל(!) שיהיה פשוט ונוח ושתתחיל לכתוב אותו כבר (ולא תנסה לאפיין/לעצב אותו במשך ימים). אני יענה על הנק' שהעלת: 1. הכי חשוב - כתבת שאתה נוהג לכתוב המון Interface-ים: א. אין שום קשר בין זה לבין אי היכולת לכתוב תחיליות אבל אם זה רצונך, מי אני שאגיד אחרת. ב. לפעמים עושים שימוש מופרז בinterface-ים ומנסים לעשות הכל כ"כ ג'נרי ששוכחים שצריך בסופו של דבר להוציא תוצר מסוים. החוכמה לדעתי היא לקבוע ממשק פשוט וכללי, לא להתחבט בנושא במשך ימים, ובמידה ולאחר מכן אתה יודע שתיהיה צריך להוסיף לו, תבנה אותו באופן שיהיה לך נוח יחסית לעשות refactoring - אבל שוב, אל(!) תנסה לחשוב שבעת התכנון אתה צריך להתייחס למצבים שהם בלתי אפשריים רק בשביל להגיד "הקוד הזה ג'נרי כ"כ שהוא יתאים גם אם נרצה לשנות את הלוגיקה לחלוטין", תחשוב SIMPLE. 2. אין שום סיבה שDocument ידע להיפתח באמצעות Editor מסוים, אם כבר Editor יקבל Document וידע לפתוח אותו. 3. אני לא רואה מה הבעיה בענין שDocument תיהיה מחלקה, יש לך סוגים שונים של Document - סבבה, תירש ממנו ותממש. גם PDF, גם ציור וגם גרף יכולים להחשב לחלק מDocument כך שרעיונית לדעתי זה לא מהווה מכשול. 4. אתה רוצה שכל מדפסת תדפיס מסמך באופן אחר, סבבה, תוריד את הstatic, תעשה אותה virtual, תירש מן המחלקה הזו ותממש כאוות נפשך. אני לא מבין מה הבעיה, אם יש לך מחלקה שמחזיקה מערך של Document(גם אם זו מחלקה), לעבור עליהן ולשלוח אותן להדפסה אצל Printer (שהרי Document מממש את הממשק IPrintable).
 

ייוניי

New member
זה ממש לא כך

ההודעה הראשונית שלי נועדה לבדוק רעיון עיצובי מסויים שאני ממש לא סגור עליו עדיין... אבל הכיוונים שהועלו בינתיים הם לעיצוב שונה מהמקור באופן שלא מספק את הדרישות. כתבתי את הבעיה במונחים של interface בשביל להדגיש שמדובר בבעיה עיצובית ולא בבעיית יישום. ברור שאינני כותב interface להנאתי אלא רק אם אני רוצה לכתוב לפחות שני ישומים שונים שלו או שיש צורך מהותי בהפחתת צמידות, אחרת אני פשוט אכתוב מחלקה. ולגבי הנקודות שהזכרת: 1. הבעיה שאני מתחבט בה היא האם השימוש ב abstract factory כתחליף ל subtyping הוא כדאי וזו בעיה די גנרית ששווה מחשבה. כמו שהסברתי השימוש שלי ב interface-ים הוא רק במקרה הצורך, אולי הסיבה שיש לי הרבה כאלה היא שאני לא נוהג להשתמש בהורשה של מחלקות ולכן גם ראיתי בפתרון שלך כהצעה ליישום ולא לעיצוב. 2. זה נתון למחלוקת אבל אני חושב שהנורמה היא שמסמך מכיל את המידע הרלוונטי לעריכה (שאת אופיו אני לא יודע) ואילו העורך מכיל מתודות להצגה של מידע לעריכה. כך שלעורך אין מושג איך להציג מסמך לעריכה... 3. אז זהו שבילבלת אותי בכך שכתבת מתודה שאיננה ניתנת לדריסה אז חשבתי שהתכוונת למימוש סופי. 4. כאן זו כבר בעיה יותר גדולה כי מימשת שם מתודה סטטית מה שאומר שאם אני מחליף את זה במתודה וירטואלית אני צריך לשנות את כל הקריאות בשאר המערכת וזה יקר לי. אבל גלשתי קצת מהנושא העיקרי, השאלה שרציתי להתמודד איתה היא בהנחה שיש לי כבר כמה מימושים שונים של Document וכמה מימושים של Printer וכו'... ואני רוצה ליצור מצב שבו כל Document הוא גם Printable מבחינת עיצוב, מהי הדרך הנכונה לעשות זאת ובאילו תנאים?
 

עידו פ

New member
כמה אפשרויות כפי שאני רואה את זה

כאשר מדובר בשני ממשקים המגדירים אופן עבודה, ואתה רוצה ליצור ישות שיודעת לבצע את כולם, ניתן לעשות את זה באחד האמצעים הבאים: 1. הגדרת ממשק IPrintableDocument שיורש את שני הממשקים הנ"ל ובכך מגדיר ממשק המחייב את המחלקה הממשת לטפל גם בהדפסה וגם במסמך. אם יש סוגים שונים של מסמכים שניתנים להדפסה, כל אחד יכול לרשת מהממשק ולממש באופן שונה את הפעולות 2. ירושה משני הממשקים - הייתי עושה את זה רק בשביל לחסוך את הממשק הנוסף במקרה ומדובר במקרה חדש פעמי של מסמך שגם ניתן להדפסה. מצד שני, אם מדובר במערכת לניהול מסמכים שגם מאפשר הדפסה, הייתי יוצא מנקודת הנחה שיכולים להיות הרבה סוגי מסמכים שניתנים להדפסה בצורות שונות ולכן הפתרון הנ"ל לא כדאי בגלל הכפילות (NxM אופציות כמספר סוגי המסמכים והמדפסות) ובמקרה זה הייתי מגדיר ממשק IPrintableDocument שמכיל הפניה לאובייקט IPrintable ואובייקט IDocument. בשביל פתרון זה מומלץ להגדיר פרוטוקול מסודר שמטפל באופן העברת הנתונים מ-Document ל-Printer (מה מעבירים, איך מעבירים, מתי מעבירים ומה לצפות כתשובה)
 

עידו פ

New member
תיקון עצמי

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

ייוניי

New member
זה די דומה לשתי האופציות שהצגתי

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