Class modifiers: sealed, final, base, interface
Əvvəlcə üç əlaqə növünü ayır — modifierlər məhz bunları icazə verir və ya qadağan edir:
extends— implementasiyanı miras alırsan. Bir dənə super class ola bilər,super.method()işləyir, konstruktorlar zəncirlə çağırılır.implements— yalnız interfeys müqaviləsini götürürsən. Dart-da hər class avtomatik olaraq eyni adlı interfeys yaradır, ona görə istənilən konkret class-ıimplementsetmək mümkündür; amma bu zaman bütün üzvləri özün yazmalısan, heç nə miras qalmır.with— mixin qoşursan: implementasiya gəlir, amma "is-a" iyerarxiyası qurmadan və neçə dənə istəsən.
Dart 3-ə qədər bu azadlıq tam idi: paket istifadəçisi sənin istənilən class-ını extend və ya implement edə bilirdi, sən isə paketdə metod əlavə etsən onların kodu sınırdı. Class modifiers məhz bu problemi həll etmək üçün gəldi.
| Modifier | Kitabxanadan KƏNARDA icazə verir | Nə üçündür |
|---|---|---|
| (modifiersiz) `class` | new, extends, implements | Dart 2 davranışı — ən sərbəst, ən qorumasız |
| `abstract class` | extends, implements (new yox) | Tam olmayan tip — birbaşa instansiya edilə bilməz |
| `base class` | yalnız extends; alt tiplər də base/final/sealed olmalıdır | Hər instansiyanın sənin implementasiyanı daşımasına zəmanət |
| `interface class` | yalnız implements | Müqavilə vermək, amma implementasiyanı miras verməmək |
| `final class` | nə extends, nə implements — yalnız istifadə | Gələcəkdə breaking change olmadan üzv əlavə etmək azadlığı |
| `sealed class` | heç nə (implicitly abstract + final) | Alt tiplərin tam siyahısı məlum — exhaustive switch |
| `mixin class` | extends, implements və `with` | Həm class, həm mixin kimi işlədilə bilən tip |
Sealed class — Dart 3-ün əsas yeniliyi. sealed bir class-ı eyni anda abstract və final edir və əlavə olaraq kompilyatora deyir: bu tipin bütün birbaşa alt tipləri eyni kitabxanadadır.
Bundan iki nəticə çıxır:
switchifadəsi exhaustive yoxlanılır: bütün variantları yazsandefaultşaxəsi lazım gəlmir.- Yeni variant əlavə edəndə
default-suz bütün switch-lər kompilyasiya olunmur — kompilyator sənə düzəldiləsi yerlərin siyahısını verir. Bu, run-time xətanı compile-time xətasına çevirməkdir.
Müasir Dart-da Result, LoadState, AuthState kimi modelləri məhz sealed hierarchy + pattern matching ilə yazırlar. Kombinasiyalar da mümkündür və mənalıdır: abstract interface class — saf interfeys idiomu; sealed isə heç nə ilə birləşmir, çünki artıq özündə abstract + final daşıyır.
Kitabxana müəllifi kimi hansını seçmək? Praktik qayda:
- Daxili (application) kodda çox vaxt heç bir modifier lazım deyil — komanda onsuz da bütün kodu görür.
- Paket yazırsansa default olaraq `final` seç. Sonradan
final-ı götürmək breaking change deyil, əlavə etmək isə breaking change-dir. - Yalnız müqavilə vermək istəyirsənsə (istifadəçi öz implementasiyasını yazsın, test-də fake qursun) —
abstract interface class. - Hər alt tipin sənin state və invariant-larını daşımasına ehtiyac varsa —
base. - Bağlı variant çoxluğunu modelləşdirirsənsə —
sealed.
Diqqət: base "yoluxucu"dur — base class-ın hər alt tipi də base, final və ya sealed olmalıdır. Bu qəsdəndir: implementasiya zəncirinin heç bir yerində kimsə implements ilə boşluq aça bilməsin.
Müsahibə ipucu. İki sual demək olar zəmanətlidir. Birincisi: "`extends` və `implements` fərqi nədir?" — güclü cavabda mütləq de ki, Dart-da hər class implicit interfeys yaradır, ona görə implements konkret class üzərində də işləyir, sadəcə heç bir implementasiya miras qalmır; testdə fake qurmağın ən sadə yolu budur. İkincisi: "sealed class-ı nə vaxt enum-a üstün tutursan?" — cavabı bir cümləyə yığ: variantların hər birinin öz datası varsa sealed, sadəcə adlar siyahısıdırsa enum. Ən çox edilən səhv: sealed-i "final class"-ın sinonimi kimi izah etmək. Fərq exhaustiveness-dədir — final sadəcə qapayır, sealed isə kompilyatora tam siyahını verir.
📚 Mənbələr və sənədlər
- Class modifiersrəsmidart.dev