Jaka jest zaleta korzystania z klasy abstrakcyjnej zamiast cechy (oprócz wydajności)? Wygląda na to, że klasy abstrakcyjne można w większości przypadków zastąpić cechami.
371
Mogę wymyślić dwie różnice
Istnieje część w Programowaniu w Scali o nazwie „Aby cechować, czy nie cechować?” który odpowiada na to pytanie. Ponieważ pierwsza edycja jest dostępna online, mam nadzieję, że przytoczę tutaj wszystko. (Każdy poważny programista Scala powinien kupić książkę):
Jak wspomniano @Mushtaq Ahmed, cecha nie może mieć żadnych parametrów przekazywanych do głównego konstruktora klasy.
Kolejną różnicą jest leczenie
super
.Więcej informacji znajduje się w dalszej części rozdziału 12 .
Edycja 1 (2013):
Istnieje niewielka różnica w zachowaniu klas abstrakcyjnych w porównaniu do cech. Jedną z reguł linearyzacji jest to, że zachowuje hierarchię dziedziczenia klas, która ma tendencję do popychania klas abstrakcyjnych na później w łańcuchu, podczas gdy cechy mogą być z powodzeniem mieszane. W pewnych okolicznościach faktycznie lepiej jest znajdować się na drugiej pozycji linearyzacji klas , więc można do tego użyć klas abstrakcyjnych. Zobacz ograniczanie linearyzacji klas (kolejność mieszania) w Scali .
Edycja 2 (2018):
Począwszy od Scali 2.12, zachowanie zgodności binarnej cechy uległo zmianie. Przed 2.12 dodanie lub usunięcie elementu do cechy wymagało ponownej kompilacji wszystkich klas, które dziedziczą tę cechę, nawet jeśli klasy się nie zmieniły. Wynika to ze sposobu, w jaki cechy zostały zakodowane w JVM.
Począwszy od Scali 2.12, cechy kompilują się do interfejsów Java , więc wymagania nieco się zmniejszyły. Jeśli cecha spełnia którekolwiek z poniższych kryteriów, jej podklasy nadal wymagają ponownej kompilacji:
Ale jeśli ta cecha nie, możesz ją teraz zaktualizować bez naruszenia zgodności binarnej.
źródło
If outside clients will only call into the behavior, instead of inheriting from it, then using a trait is fine
- Czy ktoś mógłby wyjaśnić, jaka jest tutaj różnica?extends
kontrawith
?extends
iwith
. Jest to czysto składniowe. Jeśli odziedziczysz po wielu szablonach, pierwszy dostajeextend
, wszystkie inne dostająwith
, to wszystko. Pomyślwith
jak przecinkami:class Foo extends Bar, Baz, Qux
.Niezależnie od tego, co jest warte, Odersky i wsp. Programowanie w Scali zaleca, aby w razie wątpliwości używać cech. W razie potrzeby zawsze możesz zmienić je na klasy abstrakcyjne.
źródło
Poza tym, że nie można bezpośrednio rozszerzyć wielu klas abstrakcyjnych, ale można łączyć wiele cech w klasę, warto wspomnieć, że cechy można ustawiać jeden na drugim, ponieważ super wywołania cechy są dynamicznie powiązane (odnosi się to do klasy lub cechy mieszanej wcześniej obecne).
Z odpowiedzi Thomasa na Różnice między klasą abstrakcyjną a cechą :
źródło
Podczas rozszerzania klasy abstrakcyjnej pokazuje to, że podklasa jest podobnego rodzaju. Wydaje mi się, że nie jest tak w przypadku używania cech.
źródło
W Programowaniu Scali autorzy twierdzą, że klasy abstrakcyjne tworzą klasyczną relację obiektową typu „jest-a”, podczas gdy cechy są skalowaną kompozycją.
źródło
Klasy abstrakcyjne mogą zawierać zachowanie - można sparametryzować je za pomocą argumentów konstruktora (których cechy nie mogą) i reprezentować działającą jednostkę. Zamiast tego cechy reprezentują tylko jedną funkcję, interfejs jednej funkcjonalności.
źródło
trait Enumerable
pomocą wielu funkcji pomocniczych, nie nazwałbym ich zachowaniem, a jedynie funkcjonalnością związaną z jedną funkcją.źródło