JavaRush /Blog Java /Random-PL /Domyślne metody w interfejsach

Domyślne metody w interfejsach

Opublikowano w grupie Random-PL
Każda nowa wersja Java różni się od poprzednich. Oto przykład zmian w materiale, który omówiliśmy: Przed Javą 5 enumw języku nie było żadnych znaków „”.
Domyślne metody w interfejsach - 1
Podobnie Java 8 różni się zauważalnie od Java 7. Większość naszych wykładów jest napisana w 7. wersji tego języka, ale oczywiście nie będziemy ignorować ważnych innowacji. Ponieważ w tym wykładzie mówimy o interfejsach, przyjrzyjmy się jednej aktualizacji - metodom domyślnym w interfejsach . Wiesz już, że interfejs nie implementuje . Jego zadaniem jest opisanie, jakie zachowanie powinny mieć wszystkie obiekty go implementujące . Jednak dość często programiści napotykali sytuacje, w których implementacja metody we wszystkich klasach była taka sama. Spójrzmy na przykład naszego starego samochodu:
public interface Car {

   public void gas();

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

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

   @Override
   public void brake() {
       System.out.println("Тормоз!");
   }
}


public class Truck implements Car {

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

   @Override
   public void brake() {
       System.out.println("Тормоз!");
   }
}


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

   @Override
   public void brake() {
       System.out.println("Тормоз!");
   }
}
Jak myślisz, jaki jest główny problem z tym kodem? Prawdopodobnie zauważyłeś, że napisaliśmy kilka tego samego kodu! Ten problem jest powszechny w programowaniu i należy go unikać. Inną sprawą jest to, że przed wydaniem Java 8 nie było żadnych specjalnych opcji rozwiązań. Kiedy ukazała się ta wersja, stało się możliwe zdefiniowanie metod domyślnych i zaimplementowanie ich bezpośrednio w interfejsie! Oto jak to się robi:
public interface Car {

   public default void gas() {
       System.out.println("Газ!");
   }

   public default void brake() {
       System.out.println("Тормоз!");
   }
}

public class Sedan implements Car {

}

public class Truck implements Car {

}

public class F1Car implements Car {

}
Teraz metody gas()i brake(), które były takie same dla wszystkich maszyn, są zawarte w interfejsie i duplikat kodu nie jest potrzebny. Co więcej, metody są dostępne w każdej z klas!
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();
   }
}
Co się stanie, jeśli istnieje 100 klas z metodą gas(), ale tylko 99 z nich zachowuje się tak samo? To wszystko psuje, a domyślna metoda w tym przypadku nie zadziała? Oczywiście, że nie :) Domyślne metody interfejsów można zastąpić.
public class UnusualCar implements Car {
   @Override
   public void gas() {
       System.out.println("Эта машина газует по-другому!");
   }

   @Override
   public void brake() {
       System.out.println("Эта машина тормозит по-другому!");
   }
}
Wszystkie pozostałe 99 typów maszyn zaimplementuje metodę domyślną, a klasa UnusualCar– wyjątek – nie zepsuje ogólnego obrazu i spokojnie określi jej zachowanie. Dziedziczenie wielokrotne w interfejsach Jak już wiesz, w Javie nie ma dziedziczenia wielokrotnego. Powodów jest wiele, przyjrzymy się im szczegółowo w osobnym wykładzie. W innych językach, na przykład w C++, jest odwrotnie. Bez wielokrotnego dziedziczenia powstaje poważny problem: ten sam obiekt może mieć wiele różnych cech i „zachowań”. Przykład z życia: dla naszych rodziców jesteśmy dziećmi, dla nauczycieli jesteśmy uczniami, dla lekarzy jesteśmy pacjentami. W życiu pojawiamy się w różnych rolach i odpowiednio zachowujemy się inaczej: oczywiście inaczej będziemy rozmawiać z nauczycielami niż z bliskimi przyjaciółmi. Spróbujmy przełożyć tę sytuację na kod. Wyobraźmy sobie, że mamy dwie klasy: Staw i Ptaszarnia. Do stawu potrzebne są ptaki pływające, a do woliery latające. Aby to zrobić, stworzyliśmy dwie klasy bazowe - FlyingBirdi Waterfowl.
public class Waterfowl {
}

public class FlyingBird {
}
W związku z tym do woliery wyślemy te ptaki, których klasy są odziedziczone FlyingBird, a do stawu - te, które pochodzą Waterfowl. Wszystko wydaje się proste. Ale co zrobimy, jeśli będziemy musieli gdzieś zidentyfikować kaczkę? Zarówno pływa, jak i lata. Ale nie mamy dziedziczenia wielokrotnego. Na szczęście Java zapewnia wiele implementacji interfejsów. Jeśli klasa nie może dziedziczyć od kilku rodziców, wdrożenie kilku interfejsów jest łatwe! Nasza kaczka może zarówno latać, jak i pływać :) Wystarczy użyć interfejsów FlyingBird, a Waterfowlnie klas, aby osiągnąć zamierzony efekt.
public class Duck implements FlyingBird, Waterfowl {

   //методы обоих интерфейсов легко объединяются в одном классе

   @Override
   public void fly() {
       System.out.println("Летим!");
   }

   @Override
   public void swim() {

       System.out.println("Плывем!");
   }
}
Dzięki temu nasz program zachowuje elastyczne zarządzanie klasami, a w połączeniu z implementacją metod domyślnych nasza możliwość definiowania zachowania obiektów staje się niemal nieograniczona! :)
Komentarze
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION