İçeriğe geç
academia.sh

Ders 09 / 23

Sınıflar ve Erişim Belirteçleri

Sınıf alanlarının tiplenmesi, görünürlük belirteçlerinin derleme anındaki ve çalışma zamanındaki karşılıkları, parametre özellikleri, soyut sınıflar ve implements bildirimi.

İçindekiler

Buraya kadarki sözleşmeler yalnızca veriyi ve işlem imzalarını tanımladı; gerçekleştirim her seferinde ayrı bir fonksiyondan geldi. Sınıflar bu ikisini bir arada tutar.

JavaScript’te Nesneler ve Fonksiyonlar kursunda sınıf sözdiziminin prototip modeline karşılığı kurulmuştu. TypeScript bu sözdizimine üç şey ekler: alanların ve yöntemlerin tipleri, görünürlük belirteçleri (access modifier) ve soyut bildirimler. Bu eklerin bazıları silinir, bazıları kod üretir; ayrım bu dersin merkezidir.

Alanların Tiplenmesi ve Görünürlük

Ölçüm kayıtlarını toplayan bir defter sınıfı, üç farklı görünürlük biçimini bir arada gösterir:

interface Olcum {
  readonly kimlik: string;
  deger: number;
}

class OlcumDefteri {
  private kayitlar: Olcum[] = [];
  #gizliSayac = 0;

  constructor(readonly ad: string) {}

  ekle(olcum: Olcum): void {
    this.kayitlar.push(olcum);
    this.#gizliSayac += 1;
  }

  get sayi(): number {
    return this.kayitlar.length;
  }
}

const defter = new OlcumDefteri("kazan-2");
defter.ekle({ kimlik: "s-01", deger: 21.4 });
console.log(defter.ad, defter.sayi);

Dosya defter.ts adıyla tsc --strict --target es2022 defter.ts komutuyla derlendiğinde üretilen JavaScript:

"use strict";
class OlcumDefteri {
    ad;
    kayitlar = [];
    #gizliSayac = 0;
    constructor(ad) {
        this.ad = ad;
    }
    ekle(olcum) {
        this.kayitlar.push(olcum);
        this.#gizliSayac += 1;
    }
    get sayi() {
        return this.kayitlar.length;
    }
}
const defter = new OlcumDefteri("kazan-2");
defter.ekle({ kimlik: "s-01", deger: 21.4 });
console.log(defter.ad, defter.sayi);

node defter.js çıktısı kazan-2 1dir. Çıktıda üç şey görülür.

private silinmiştir. private kayitlar alanı, derlenmiş kodda kayitlar olarak durur ve dışarıdan okunabilir. #gizliSayac durmaktadır. Bu, TypeScript’e değil JavaScript’e ait bir özelliktir ve çalışma zamanında zorunlu tutulur.

constructor(readonly ad: string) yazımı kod üretmiştir. Buna parametre özelliği (parameter property) denir: yapıcı parametresine bir görünürlük veya readonly belirteci konduğunda derleyici, aynı adlı bir alan bildirir ve atamayı ekler. Numaralandırma gibi, bu da tip silme ilkesinin istisnasıdır.

Farkın sonucu, derlenmiş sınıf doğrudan JavaScript’ten kullanıldığında gözlenir. Aşağıdaki dosya, yukarıda üretilen sınıf gövdesini alıp üç sorgu ekler:

class OlcumDefteri {
    ad;
    kayitlar = [];
    #gizliSayac = 0;
    constructor(ad) {
        this.ad = ad;
    }
    ekle(olcum) {
        this.kayitlar.push(olcum);
        this.#gizliSayac += 1;
    }
    get sayi() {
        return this.kayitlar.length;
    }
}

const defter = new OlcumDefteri("kazan-2");
defter.ekle({ kimlik: "s-01", deger: 21.4 });

console.log(Object.keys(defter));
console.log(defter.kayitlar);
console.log(defter.gizliSayac);
[ 'ad', 'kayitlar' ]
[ { kimlik: 's-01', deger: 21.4 } ]
undefined

kayitlar alanı hem sayılabilir hem okunabilir; #gizliSayac ise gizliSayac adıyla erişilmeye çalışıldığında undefined verir, çünkü öyle bir genel alan yoktur.

Derleme anında ikisi de korunur, ama farklı tanılarla:

class OlcumDefteri {
  private kayitlar: number[] = [];
  #sayac = 0;

  ekle(deger: number): void {
    this.kayitlar.push(deger);
    this.#sayac += 1;
  }
}

const defter = new OlcumDefteri();
defter.ekle(21.4);
console.log(defter.kayitlar);
console.log(defter.#sayac);
i1.ts(13,20): error TS2341: Property 'kayitlar' is private and only accessible within class 'OlcumDefteri'.
i1.ts(14,20): error TS18013: Property '#sayac' is not accessible outside class 'OlcumDefteri' because it has a private identifier.

Seçim ölçütü şudur: görünürlük bir tasarım kuralıysa private, bir güvenlik sınırıysa #. Ekip içinde yanlış kullanımı önlemek için private yeterlidir ve derleme anında yakalar. Kütüphane sınırında, denetlenmeyen kodun erişmemesi gerekiyorsa # kullanılır.

protected belirteci de yalnızca derleme anında geçerlidir ve alanı sınıfın kendisine ve alt sınıflarına açar.

Soyut Sınıflar

Soyut sınıf (abstract class), gerçekleştirilmemiş üyeler bildirebilen ve doğrudan örneklenemeyen sınıftır. Ölçüm kaynağı sözleşmesi, ortak bir davranış da taşıyacaksa arayüz yerine soyut sınıfla yazılır:

interface Olcum {
  kimlik: string;
  deger: number;
}

abstract class OlcumKaynagi {
  abstract readonly ad: string;
  protected abstract sonraki(): Olcum | null;

  tumu(): Olcum[] {
    const toplanan: Olcum[] = [];
    let kayit = this.sonraki();
    while (kayit !== null) {
      toplanan.push(kayit);
      kayit = this.sonraki();
    }
    return toplanan;
  }
}

class DiziKaynagi extends OlcumKaynagi {
  readonly ad = "dizi";
  private sira = 0;

  constructor(private readonly kayitlar: readonly Olcum[]) {
    super();
  }

  protected sonraki(): Olcum | null {
    return this.sira < this.kayitlar.length ? this.kayitlar[this.sira++] : null;
  }
}

const kaynak = new DiziKaynagi([
  { kimlik: "s-01", deger: 21.4 },
  { kimlik: "s-02", deger: 22.1 },
]);
console.log(kaynak.ad, kaynak.tumu().length);

Çıktı dizi 2dir.

Yapı, iki tür üyeyi ayırır. sonraki yöntemi soyuttur: her kaynak farklı gerçekleştirir. tumu yöntemi ise somuttur ve sonraki üzerine kurulmuş ortak davranışı taşır. Alt sınıf yalnızca değişen parçayı yazar.

Dosyanın sonuna, bir boş satırdan sonra const olmaz = new OlcumKaynagi(); satırı eklenirse derleyici şu tanıyı verir:

i2.ts(40,15): error TS2511: Cannot create an instance of an abstract class.

abstract belirteci de silinir — derlenmiş çıktıda sıradan bir sınıf kalır ve JavaScript tarafından örneklenebilir. Yasak, derleme anına aittir.

implements

Bir sınıfın belirli bir sözleşmeyi karşıladığı implements ile bildirilir:

interface OlcumKaynagi {
  readonly ad: string;
  sonraki(): number | null;
}

class BosKaynak implements OlcumKaynagi {
  readonly ad = "bos";
}
i4.ts(6,7): error TS2420: Class 'BosKaynak' incorrectly implements interface 'OlcumKaynagi'.
  Property 'sonraki' is missing in type 'BosKaynak' but required in type 'OlcumKaynagi'.

implements bir sınama bildirimidir, bir kalıtım değil. Sınıfa hiçbir üye eklemez; yalnızca sözleşmeye uygunluğu denetler ve tanıyı sınıfın bildirim satırında verir. Bu bildirim olmasaydı sınıf yine derlenir, uyumsuzluk ancak kullanım yerinde ortaya çıkardı.

implements yazımı tümüyle silinir; derlenmiş çıktıda izi kalmaz.

Soyut Sınıf mı, Arayüz mü

İki araç örtüşür; ölçüt şudur:

Ölçüt Arayüz Soyut sınıf
Ortak gerçekleştirim taşır Hayır Evet
Çalışma zamanı kodu üretir Hayır Evet
Bir tip birden çoğunu karşılar Evet Hayır (tek üst sınıf)
Durum (alan değeri) taşır Hayır Evet

Yalnızca sözleşme gerekiyorsa arayüz. Silinir, birden çoğu birlikte kullanılabilir ve gerçekleştirimi bağlamaz.

Sözleşmeyle birlikte ortak davranış gerekiyorsa soyut sınıf. Yukarıdaki tumu yöntemi bunun örneğidir: tek yerde yazılmış, tüm kaynaklarda geçerli bir algoritma.

Programlama Temelleri kursunda tanıtılan sınıf değişmezi kavramı burada tip düzeyinde destek bulur: private alanlar üzerinde tutulan bir değişmez, dışarıdan bozulamaz — çünkü alanlara yalnızca sınıfın kendi yöntemleri erişebilir ve derleyici bunu sınar.

Özet

  • Sınıf alanlarının ve yöntemlerinin tipleri silinir; private ve protected yalnızca derleme anında geçerlidir, # ile bildirilen alanlar çalışma zamanında da korunur.
  • Parametre özelliği (constructor(readonly ad: string)) kod üretir: alan bildirimi ve atama derleyici tarafından eklenir.
  • Soyut sınıf, gerçekleştirilmemiş üyeler bildirir ve doğrudan örneklenemez; abstract belirteci derlenmiş çıktıda kalmaz.
  • implements bir sınama bildirimidir; sınıfa üye eklemez, tanıyı bildirim satırında verir ve tümüyle silinir.
  • Yalnızca sözleşme için arayüz, sözleşmeyle birlikte ortak davranış için soyut sınıf seçilir.

Sonraki Adım

Sınıf yöntemleri ve tek başına duran fonksiyonlar, bu derste yalnızca kullanıldı; tiplerinin nasıl yazıldığı ele alınmadı. Bir fonksiyonun tipi parametre ve dönüş tiplerinden ibaret değildir: seçmeli parametreler, kalan parametreler, aşırı yükleme ve this bağlamı da tipin parçasıdır. Sonraki ders fonksiyon tiplerini ayrıntılı kuracak.

İlerlemeni kaydetmek ve not almak için Giriş yap

Notlarım

Not almak için giriş yapmalısın.

Aramak için yazmaya başlayın.

↑↓ Esc gezin · aç · kapat