373. Virtual Extension methods

בהמשך לטיפ על Single Abstract Method הבא אליו בJava 8, הנה עוד Feature שמגיע אלינו מJava 8:

הFeature נקרא Virtual Extension Methods.

על Extension Methods בC# דיברנו כבר לא מעט (טיפים 66-75 וגם אחר כך).

בגדול Extension Methods נותנים לנו שני דברים מגניבים:

  • אופציה “להוסיף” מתודות לTypeים שכבר קיימים (טיפ מספר 75 למשל)
  • אופציה לקבל בחינם מתודות לממשקים ע”י שימוש בפונקציות שהם חושפים (טיפ מספר 84)

היכולת הראשונה יכולה לאפשר לנו יכולות יפות (כמו הרבה מהדוגמאות שראינו), אבל יכולה גם לזבל לנו את הIntellisense בExtension Methods לא רלוונטיים במידה והוספנו Reference ועשינו using לא נכון.

בנוסף, ייתכן כי נשתמש בExtension Method שאין לו “תמיכה של היצרן”, כלומר הוא בד”כ לא נכתב על ידי מי שכתב את המחלקה המקורית, אלא ע”י מישהו חיצוני.

בJava החליטו שהם מממשים Extension Methods בצורה אחרת, כנראה בגלל הבעיות האלה.

איך זה עובד?

נדגים על הדוגמה של טיפ מספר 75.

נניח שיש לנו את הממשק הזה:

1
2
3
4
5
6
interface Turnable
{
public void turnLeft();
public void turnOpposite();
public void turnRight();
}

אנחנו רוצים להציע מימוש דיפולטי לTurnOpposite וTurnRight ע"י TurnLeft.

בJava 8 נוכל לעשות זאת כך:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
interface Turnable
{
public void turnLeft();
public void turnOpposite() default
{
for (int i = 0; i < 2; i++)
{
this.turnLeft();
}
};
public void turnRight() default
{
for (int i = 0; i < 3; i++)
{
this.turnLeft();
}
};
}

מה שקורה כאן זה שכשנממש את הממשק Turnable, נצטרך לממש רק את הפונקציה TurnLeft, ונקבל בחינם מימושים לפונקציות TurnRight וTurnOpposite.

עם זאת, קיימת לנו האופציה לדרוס את TurnRight וTurnOpposite למימושים אחרים משלנו.

אם נרצה למנוע מהמממש של הממשק שלנו את האפשרות של לדרוס את הפונקציות האלה, נוכל להחליף את המילה default בfinal:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
interface Turnable
{
// Must override
public void turnLeft();
// Can override
public void turnOpposite() default
{
for (int i = 0; i < 2; i++)
{
this.turnLeft();
}
};
// Can't override
public void turnRight() final
{
for (int i = 0; i < 3; i++)
{
this.turnLeft();
}
};
}

זה מזכיר קצת את הסיפור של מחלקה אבסטרקטית.

הדבר הזה מאפשר להתגבר על החסרונות של Extension Methods:

נוכל להוסיף "Extension Methods" רק לממשקים שאנחנו כתבנו.

מצד אחד זו הגבלה, כיוון שלא נוכל להוסיף Extension Methods יפים לטיפוסים שלא שלנו.

מצד שני, זה מאפשר יותר סדר ושליטה על המתודות שמופיעות בIntellisense, ומאפשר Api נקי יותר.

אישית, הדבר שהכי אהבתי כאן זה העובדה שאפשר לממש Extension Method ולדרוס את המימוש הדיפולטי. זה Feature שחסר בC#, וכנראה בלתי אפשרי לעשות בגלל האופן בו מימשו Extension Methods בשפה.

המשך יום מורחב עם קפה טוב.

שתף