CodeGym /בלוג Java /Random-HE /שיטות ברירת מחדל בממשקים
John Squirrels
רָמָה
San Francisco

שיטות ברירת מחדל בממשקים

פורסם בקבוצה
כל גרסה חדשה של Java שונה מאלה שהגיעו קודם לכן. הנה דוגמה לשינויים בחומר שסקרנו: לפני Java 5, לשפה לא היה enums. שיטות ברירת מחדל בממשקים - 1באופן דומה, Java 8 שונה באופן ניכר מ-Java 7. רוב השיעורים שלנו נכתבו עבור הגרסה ה-7 של השפה, אבל כמובן שלא נתעלם מחידושים חשובים. מכיוון שאנחנו כבר מדברים על ממשקים בשיעור זה, נשקול עדכון אחד - שיטות ברירת מחדל בממשקים . אתה כבר יודע שממשק לא מיישם התנהגות . המשימה שלו היא לתאר את ההתנהגות שחייבים להיות לכל האובייקטים שמיישמים אותו . אבל מפתחים נתקלו לעתים קרובות במצבים שבהם היישום של שיטה זהה בכל המחלקות. בואו ניקח בחשבון את דוגמא המכונית הישנה שלנו:
public interface Car {

   public void gas();

   public void brake();
}
public class Sedan implements Car {

   @Override
   public void gas() {
       System.out.println("Gas!");
   }

   @Override
   public void brake() {
       System.out.println("Brake!");
   }
}


public class Truck implements Car {

   @Override
   public void gas() {
       System.out.println("Gas!");
   }

   @Override
   public void brake() {
       System.out.println("Brake!");
   }
}


public class F1Car implements Car {
   @Override
   public void gas() {
       System.out.println("Gas!");
   }

   @Override
   public void brake() {
       System.out.println("Brake!");
   }
}
"לדעתך, מה הבעיה העיקרית עם הקוד הזה? בטח שמתם לב שכתבנו צרור של קוד חוזר! בעיה זו נפוצה בתכנות, וצריך להימנע ממנה. זה עניין אחר שפתרונות מסוימים לא היו קיימים קודם לכן. Java 8 שוחררה. עם גרסה זו הגיעה היכולת לציין שיטות ברירת מחדל וליישם אותן ישירות בתוך הממשק! כך תעשה זאת:
public interface Car {

   public default void gas() {
       System.out.println("Gas!");
   }

   public default void brake() {
       System.out.println("Brake!");
   }
}

public class Sedan implements Car {

}

public class Truck implements Car {

}

public class F1Car implements Car {

}
כעת שיטות gas()ו- brake(), שהיו זהות עבור כל המכוניות, הועברו לממשק. אין צורך בקוד חוזר. מה שכן, השיטות זמינות בכל מחלקה!
public class Main {

   public static void main(String[] args) {

       F1Car f1Car = new F1Car();
       Sedan sedan = new Sedan();
       Truck truck = new Truck();
       truck.gas();
       sedan.gas();
       f1Car.brake();
   }
}
מה אם יש 100 מחלקות עם gas()השיטה, אבל רק ל-99 מהן יש את אותה התנהגות? האם זה הורס הכל והופך את שיטת ברירת המחדל לבלתי מתאימה למצב הזה? כמובן, לא :) ניתן לעקוף שיטות ברירת מחדל בממשקים באותו אופן כמו שיטות רגילות.
public class UnusualCar implements Car {
   @Override
   public void gas() {
       System.out.println("This car accelerates differently!");
   }

   @Override
   public void brake() {
       System.out.println("This car decelerates differently!");
   }
}
כל 99 סוגי המכוניות האחרים יישמו את שיטת ברירת המחדל, והמחלקה UnusualCar, שהיא חריגה, לא תקלקל את התמונה הכוללת ותגדיר בשלווה את ההתנהגות שלה. ירושה מרובה של ממשקים. כפי שאתה כבר יודע, Java אינה תומכת בירושה מרובה. יש לכך סיבות רבות. נסתכל עליהם בפירוט בשיעור נפרד. שפות אחרות, כמו C++, אכן תומכות בזה. ללא ירושה מרובה נוצרת בעיה רצינית: לאובייקט אחד יכולים להיות כמה מאפיינים ו'התנהגות' שונים. הנה דוגמה מהחיים: אנחנו ילדים להורינו, תלמידים למורים שלנו, ומטופלים לרופאים שלנו. בחיים, אנחנו לוקחים על עצמנו תפקידים שונים, ובהתאם לכך, מתנהגים אחרת: ברור שלא היינו מדברים עם מורים כמו שאנחנו מדברים עם החברים הקרובים שלנו. בואו ננסה לתרגם את זה לקוד. תארו לעצמכם שיש לנו שני כיתות: בריכה ועופרי. עבור הבריכה, אנחנו צריכים עוף מים; עבור הציפורייה, אנחנו צריכים ציפורים מעופפות. לשם כך, יצרנו שתי מחלקות בסיס: FlyingBirdו Waterfowl.
public class Waterfowl {
}

public class FlyingBird {
}
בהתאם לכך, נשלח ציפורים שהכיתות שלהן יורשים FlyingBirdלצופר, ונשלח Waterfowlלבריכה ציפורים שיורשו. הכל נראה מאוד פשוט. אבל לאן נשלח ברווז? זה שוחה ועף. ואין לנו ירושה מרובה. למרבה המזל, Java תומכת ביישום מרובים של ממשקים. למרות שכיתה לא יכולה לרשת כמה הורים, היא יכולה בקלות ליישם כמה ממשקים! הברווז שלנו יכול להיות גם ציפור מעופפת וגם עוף מים :) אנחנו פשוט צריכים לעשות FlyingBirdולהתממשק Waterfowlולא שיעורים כדי להשיג את התוצאה הרצויה.
public class Duck implements FlyingBird, Waterfowl {

   // The methods of both interfaces can be easily combined into one class

   @Override
   public void fly() {
       System.out.println("Fly!");
   }

   @Override
   public void swim() {

       System.out.println("Swim!");
   }
}
בהתאם לכך, התוכנית שלנו שומרת על הגמישות של מחלקות, ובשילוב עם שיטות ברירת מחדל, היכולת שלנו להגדיר התנהגות של אובייקטים הופכת כמעט בלתי מוגבלת! :)
הערות
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION