Mixin-lər
Mixin — iyerarxiya qurmadan davranışı bir neçə class arasında bölüşdürmək üsuludur. Dart-da tək miras var (extends bir dənə), mixin isə istənilən qədər qoşula bilər: class Duck extends Animal with Swimmer, Flyer {}.
Elan:
mixin Swimmer { ... }— sərbəst mixin, istənilən class-a qoşula bilər.mixin Swimmer on Animal { ... }— `on` clause super class-ı məhdudlaşdırır: bu mixin yalnızAnimalalt tiplərinə qoşula bilər. Əvəzində mixin içindəAnimal-ın üzvlərinə (name,move()) müraciət etmək vəsuper.move()çağırmaq mümkün olur.mixin class Timestamped { ... }— Dart 3-dən: həmwith, həm dəextendsilə istifadə oluna bilən tip.
Məhdudiyyət: mixin-in konstruktoru olmur. Sahə elan edə bilər (int strokes = 0;), amma parametr qəbul edə bilməz — buna görə konfiqurasiya lazım olan davranış üçün mixin yox, kompozisiya seçilir.
Linearizasiya — mixin-lərin ən çox soruşulan hissəsi. class C extends B with M1, M2 yazanda Dart düz bir zəncir qurur:
B ← B+M1 ← B+M1+M2 ← C
Yəni mixin-lər soldan sağa tətbiq olunur və hər biri özündən əvvəlkinin üstünə "qoyulur". Nəticələr:
- Metod axtarışı sağdan sola gedir:
C→M2→M1→B. Yəni sonuncu mixin qalib gəlir. - Mixin içindəki
super.method()çağırışı zəncirdə soldakına gedir —M2-ninsuper-iM1-dir,M1-insuper-iB. - Sıranı dəyişmək davranışı dəyişir:
with M1, M2iləwith M2, M1fərqli nəticə verir. Bu, whiteboard sualının tam mərkəzidir.
Məhz bu zəncir sayəsində mixin-lər "yığılan" (stackable) davranış yaza bilir: logging, validation, retry — hər biri super-i çağırıb üstünə öz işini əlavə edir.
| Yanaşma | Nə verir | Nə vaxt seç |
|---|---|---|
| Miras — `extends` | Tək valideyn, `super`, konstruktor zənciri, "is-a" münasibəti | Real taksonomiya varsa (`Cat extends Animal`) və bir səviyyə kifayətdirsə |
| Mixin — `with` | İstənilən sayda, iyerarxiyasız davranış; `on` ilə kontekst tələbi | Eyni davranış bir-biri ilə bağlı olmayan class-larda təkrarlanırsa |
| Kompozisiya — sahə kimi saxlamaq | Tam nəzarət, asılılığı dəyişdirmək (test-də fake), konfiqurasiya | Davranış konfiqurasiya tələb edirsə və ya runtime-da dəyişməlidirsə |
| `implements` | Yalnız müqavilə, sıfır implementasiya | Tip uyğunluğu lazımdırsa (fake, adapter) |
Mixin nə vaxt səhv seçimdir? Praktik siqnallar:
- Davranışa konstruktor parametri lazımdırsa — mixin bunu edə bilmir.
- Davranışı test-də əvəzləmək (fake ilə) lazımdırsa — mixin class-a "yapışıb", onu ayırmaq mümkün deyil.
- Mixin
onilə çox spesifik tipə bağlanıbsa və yalnız bir class-da istifadə olunursa — bu, sadəcə həmin class-ın metodudur, mixin-ə ehtiyac yoxdur. - Ad toqquşması riski: iki mixin eyni adlı metod verirsə, sonuncu səssizcə qalib gəlir. Kompilyator xəbərdarlıq etmir, çünki bu, linearizasiyanın normal işidir.
Əvəzində mixin-in doğru istifadə yerləri: Comparable-a bənzər əməliyyat dəstləri, on ilə məhdudlaşdırılmış lifecycle əlavələri və dil kitabxanasındakı IterableMixin, ListMixin kimi "bir neçə abstract üzvdən onlarla hazır metod düzəldən" mixin-lər.
Müsahibə ipucu. Klassik sual: "`class C extends B with M1, M2` — `C().describe()` nə çap edir?" Doğru cavab strukturu: (1) əvvəlcə zənciri lövhədə yaz — B ← B+M1 ← B+M1+M2 ← C; (2) axtarışın sağdan sola getdiyini de — M2 qalib gəlir; (3) super-in soldakına getdiyini göstər. Cavabı bir cümlə ilə möhkəmləndir: "mixin-lər soldan sağa tətbiq olunur, metod axtarışı sağdan sola gedir, ona görə sonuncu mixin üstün olur".
Ən çox edilən səhv: mixin-i çoxlu miras (multiple inheritance) kimi izah etmək. Dart-da çoxlu miras yoxdur — mixin-lər elə məhz xətti zəncirə çevrildiyi üçün "diamond problem" heç vaxt yaranmır. Bu cümləni deməyi unutma, çox güclü təsir bağışlayır.
📚 Mənbələr və sənədlər
- Mixin-lərrəsmidart.dev