Jeśli cecha A rozszerza B, wówczas mieszanie w A daje dokładnie B plus to, co A dodaje lub rozszerza. W przeciwieństwie do tego, jeśli cecha A ma własne odwołanie, które jest jawnie wpisane jako B, wówczas najwyższa klasa nadrzędna musi również mieszać B lub potomek B (i mieszać najpierw , co jest ważne).
To najważniejsza różnica. W pierwszym przypadku dokładny typ B krystalizuje się w punkcie A, który go wydłuża. W drugim przypadku projektant klasy nadrzędnej decyduje, która wersja B zostanie użyta w punkcie, w którym klasa macierzysta jest utworzona.
Inna różnica polega na tym, że A i B zapewniają metody o tej samej nazwie. Gdzie A rozszerza B, metoda A zastępuje B. Tam, gdzie A miesza się po B, metoda A po prostu wygrywa.
Wpisane na maszynie odnośniki dają znacznie więcej swobody; połączenie między A i B jest luźne.
AKTUALIZACJA:
Ponieważ nie masz pewności co do korzyści wynikających z tych różnic ...
Jeśli korzystasz z dziedziczenia bezpośredniego, tworzysz cechę A, którą jest B + A. Ułożyłeś związek w kamień.
Jeśli użyjesz samouczenia na maszynie, każdy, kto chce użyć twojej cechy A w klasie C., może
- Wymieszaj B, a następnie A w C.
- Wymieszaj podtyp B, a następnie A w C.
- Wymieszaj A w C, gdzie C jest podklasą B.
I to nie jest granica ich opcji, biorąc pod uwagę sposób, w jaki Scala pozwala na tworzenie instancji cechy bezpośrednio z blokiem kodu jako konstruktorem.
Jeśli chodzi o różnicę między wygraną metody A , ponieważ A jest pomieszane na końcu, w porównaniu do A przedłużającego B, rozważ to ...
Kiedy łączysz sekwencję cech, za każdym razem, gdy foo()
wywoływana jest metoda , kompilator przechodzi do ostatniej wymieszanej cechy w celu jej wyszukania foo()
, a następnie (jeśli nie została znaleziona), przechodzi przez sekwencję w lewo, aż znajdzie cechę, która implementuje foo()
i wykorzystuje że. A ma również opcję wywoływania super.foo()
, która również przechodzi przez sekwencję w lewo, aż znajdzie implementację i tak dalej.
Więc jeśli A ma wpisane na maszynie odniesienie do B, a pisarz A wie, że B implementuje foo()
, A może zadzwonić super.foo()
wiedząc, że jeśli nic innego nie zapewni foo()
, B to zrobi. Jednak twórca klasy C ma możliwość upuszczenia dowolnej innej cechy, w której implementuje foo()
, a zamiast tego dostanie to.
Ponownie, jest to o wiele bardziej wydajne i mniej ograniczający niż rozciągający B i bezpośrednio dzwoniąc wersja B z użytkownikiem foo()
.