235. Another variation of the visitor pattern

בהמשך לפעם שעברה,

נוכל להפוך את הVisitor שלנו לטיפה יותר גנרי:

1
2
3
4
5
6
7
8
9
public abstract class CarVisitor<T>
{
public T Visit(CarElement element)
{
return InnerVisit((dynamic) element);
}
protected abstract T InnerVisit(CarElement element);
}

נוכל להוסיף Overloadים לשאר הפונקציות:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
public abstract class CarVisitor<T>
{
public T Visit(CarElement element)
{
return InnerVisit((dynamic)element);
}
protected abstract T InnerVisit(CarElement element);
protected virtual T InnerVisit(Wheel wheel)
{
return InnerVisit((CarElement)wheel);
}
protected virtual T InnerVisit(Door door)
{
return InnerVisit((CarElement)door);
}
protected virtual T InnerVisit(Car car)
{
return InnerVisit((CarElement)car);
}
}

עכשיו אנחנו נהנים מהיתרונות הבאים:

אפשר לדרוס את הפונקציות עבור טיפוס ספציפי (Wheel/Door/Car), אבל גם אם לא מממשים אותם, נקרא המימוש הדיפולטי.

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

בעצם אנחנו מנצלים את הDynamic Binding בשביל שינתב אותנו למתודה המתאימה.

יתרון נוסף של המימוש הזה הוא שהוא מאפשר לנו לקרוא ל"base" בצורה פשוטה יותר:

1
2
3
4
5
6
7
8
9
10
11
12
13
public class MyVisitor : CarVisitor<string>
{
protected override string InnerVisit(CarElement element)
{
return element.GetType().Name;
}
protected override string InnerVisit(Wheel wheel)
{
return base.InnerVisit(wheel) + " With a diameter of " +
wheel.Diameter;
}
}

במימוש הקודם היינו צריכים לעשות משהו כזה:

1
2
3
4
5
6
7
8
9
10
private string InnerVisit(CarElement element)
{
return element.GetType().Name;
}
private string InnerVisit(Wheel wheel)
{
return InnerVisit((CarElement)wheel) + " With a diameter of " +
wheel.Diameter;
}

שזה פחות טבעי.

סופ"ש דינאמי טוב!

שתף