Sparround

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ız Animal alt 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əm with, həm də extends ilə 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:

BB+M1B+M1+M2C

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: CM2M1B. Yəni sonuncu mixin qalib gəlir.
  • Mixin içindəki super.method() çağırışı zəncirdə soldakına gedir — M2-nin super-i M1-dir, M1-in super-i B.
  • Sıranı dəyişmək davranışı dəyişir: with M1, M2 ilə with M2, M1 fə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şmaNə verirNə vaxt seç
Miras — `extends`Tək valideyn, `super`, konstruktor zənciri, "is-a" münasibətiReal 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əbiEyni davranış bir-biri ilə bağlı olmayan class-larda təkrarlanırsa
Kompozisiya — sahə kimi saxlamaqTam nəzarət, asılılığı dəyişdirmək (test-də fake), konfiqurasiyaDavranış konfiqurasiya tələb edirsə və ya runtime-da dəyişməlidirsə
`implements`Yalnız müqavilə, sıfır implementasiyaTip 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 on ilə ç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