אחד הDesign patterns החזקים שקיימים נקרא Visitor.
הוא בגדול מאפשר לנו לבצע פעולות על משפחה של אובייקטים מבלי להכיר את המבנה הפנימי שלהם.
הדבר הזה גם מאפשר לנו “להוסיף” מתודה וירטואלית למשפחה של טיפוסים, מבלי לשנות את הקוד שלהם.
איך זה עובד?
נניח שיש לנו את המשפחה הבאה של טיפוסים:
|
|
כעת אנחנו מעוניינים להוסיף אפשרות של לצלם רכיב של המכונית.
בלי שימוש בVisitor, השיטה היא להוסיף פונקציה וירטואלית בCarElement:
|
|
ולדאוג לממש אותה בכל מחלקת בת.
יש שתי בעיות בגישה הזאת:
הבעיה הראשונה היא שעל כל פעולה שאנחנו מעוניינים להוסיף, אנחנו נצטרך להוסיף פונקציה וירטואלית כזאת. הבעיה עם זה היא שזה יכול לנפח את המחלקות שלנו. מה שיכול לקרות זה שCarElement "יממש" את הAnti-pattern שנקרא God Class, שהוא נהיה ענק ועמוס בפונקציות, כך שאנחנו לא כל כך רוצים להוסיף אליו עוד פונקציות.
הבעיה השנייה שאנחנו צריכים לדעת מהו המבנה עבור כל מחלקת בת. למה הכוונה? נניח במקום לצלם מכונית, אפשר לצלם פשוט את החלקים המרכיבים אותה. אנחנו צריכים להתחשב בזאת בדריסה במחלקה Car.
כדי לפתור את בעיות אלו, אפשר להשתמש בDesign Pattern ששמו Visitor.
לפי Design pattern זה, יש רק פונקציה אבסטרקטית אחת שצריך לממש:
|
|
כאשר הממשק ICarElementVisitor נראה ככה:
|
|
המימוש בכל אחת מהמחלקות בנות מתחשב במבנה של המחלקה:
למשל:
|
|
ואילו עבור מכונית:
|
|
הדבר הזה מאפשר לנו "להוסיף" פונקציות וירטואליות מבחוץ: אנחנו פשוט צריכים לממש אתICarElementVisitor ולעשות בו כאוות נפשנו.
למשל:
|
|
ואז נוכל לקרוא לפונקציה זו כך:
|
|
נוכל אפילו לקרוא לפונקציה זו כאילו היא הייתה פונקציה וירטואלית רגילה, ע"י שימוש בExtension Methods 😃
הדבר מאוד שימושי במקומות בהם המבנה מסובך, ומעניין אותנו להתעסק בערכים עצמם, ולא במבנה, למשל ניתוח עצי ביטויים וכו’.
המשך יום דינאמי טוב