---
title: Kalıtım
source: 'https://academia.sh/tr/kurslar/paradigmalar/kalitim'
course: 'Programlama Paradigmaları'
language: tr
updated: '2026-08-17T18:10:42+00:00'
license: 'CC BY-SA 4.0'
---

# Kalıtım

Kalıtımın iki ayrı vaadinin ayrılması: gerçekleştirim paylaşımı satır sayısıyla, alt tip ilişkisi ise üç maddelik bir ücret sözleşmesiyle ölçülür; sözleşmeye uyan ve uymayan iki alt sınıf aynı istemciyle koşturulup uymayan sürümün ürettiği yanlış sonuç sayılır.

Önceki ders tarife modülünün temsilini gizledi ve istemcilerin bildiği ayrıntıyı sıfıra
indirdi. O modül tek bir tarife biçimini gizliyordu. Gerçek bir ücretlendirme kitaplığında
tarife türü birden fazladır: sigortalı gönderi tarifesi, elden teslim tarifesi, sözleşmeli
müşteri tarifesi. Aynı adları farklı gerçekleştirimlerle karşılamanın yollarından biri bir
türü bir başkasından **türetmektir**.

**Kalıtım** (inheritance), bir sınıfın bir başkasının alanlarını ve yöntemlerini devralması
ve gerektiğinde bunların bir bölümünü kendi gerçekleştirimiyle değiştirmesidir. Programlama
Temelleri kursunda tanıtılan tanım budur. Bu derste sorulan soru şudur: türetme her zaman
bir **alt tip** (subtype) üretir mi, üretmediğinde bunu ne gösterir ve bedeli nedir.

## Kalıtımın İki Ayrı Vaadi

Kalıtım tek bir araçmış gibi anılır, ama iki ayrı şey vaat eder ve bu ikisi birbirini
gerektirmez.

Birincisi **gerçekleştirim paylaşımı**: alt sınıf, üst sınıfın kodunu tekrar yazmaz. Bu vaat
sayılabilir ve neredeyse her zaman tutulur.

İkincisi **alt tip ilişkisi**: üst tipi bekleyen her yere alt tip konabilir ve program doğru
çalışmaya devam eder. Bu vaat kodun biçimiyle değil, davranışıyla ilgilidir ve dil onu
denetlemez. `extends` yazmak birinciyi kesin olarak sağlar; ikinciyi hiç sağlamayabilir.

İkisini ayırmak için üst tipin ne söz verdiği yazılı olmalıdır. Bir üst tipin **sözleşmesi**,
yöntemlerinin girdileri ve sonuçları hakkında verdiği güvencelerdir. Alt tip bu güvenceleri
zayıflatamaz: girdi kümesini daraltamaz, sonuç hakkında verilen sözü bozamaz, üst tipin
değişmezini çiğneyemez. Bu kural Liskov yerine geçme ilkesi adıyla bilinir.

## Üst Tip ve Ücret Sözleşmesi

Kademeli tarife bir sınıfa dönüşür. Kademeler, katsayılar ve eşikler özeldir; dışarıya
`ucret`, `bolgeler` ve `asgari` açılır. `taban` yöntemi alt sınıfların kullanımına açıktır.

```js
// tarife.mjs — ust tip: kademeli tarife; ucret sozlesmesini bu sinif tanimlar
export class Tarife {
  #kademeler; #kiloBasiEk; #katsayi; #asgari;

  constructor({ kademeler, kiloBasiEk, katsayi, asgari }) {
    this.#kademeler = kademeler;
    this.#kiloBasiEk = kiloBasiEk;
    this.#katsayi = katsayi;
    this.#asgari = asgari;
  }

  get asgari() { return this.#asgari; }

  bolgeler() { return Object.keys(this.#katsayi).map(Number); }

  taban(agirlik) {
    const kademe = this.#kademeler.find(([ust]) => agirlik <= ust);
    if (kademe !== undefined) return kademe[1];
    const [sonUst, sonUcret] = this.#kademeler.at(-1);
    return sonUcret + Math.ceil((agirlik - sonUst) / 1000) * this.#kiloBasiEk;
  }

  ucret(agirlik, bolge) {
    return Math.max(Math.round(this.taban(agirlik) * this.#katsayi[bolge]), this.#asgari);
  }
}

export const AYAR = {
  kademeler: [[1000, 4500], [5000, 7000], [10000, 11000]],
  kiloBasiEk: 1800,
  katsayi: { 1: 1, 2: 1.25, 3: 1.6 },
  asgari: 5000,
};
```

`ucret` yönteminin sözleşmesi üç maddedir:

1. **S1** — Her pozitif ağırlık ve `bolgeler()` listesindeki her bölge için tanımlıdır;
   sonlu bir sayı döndürür.
2. **S2** — Sonuç asgari ücretin altına inmez.
3. **S3** — Sonuç ağırlıkla azalmaz: `a1 <= a2` ise `ucret(a1) <= ucret(a2)`.

Üçüncü madde koddan okunamaz; kademelerin artan olması ve katsayının pozitifliğinden
çıkar. Yazılı olmadığı sürece alt sınıf yazan kişinin bunu bilmesi için bir neden yoktur.
Sözleşmeyi yazmak, kalıtımın ikinci vaadini denetlenebilir kılmanın tek yoludur.

## Sözleşmeye Uyan ve Uymayan İki Alt Sınıf

İlk alt sınıf sigortalı gönderi tarifesidir: ağırlıkla artan bir sigorta payını üst sınıfın
sonucuna ekler.

```js
// sigortali.mjs — sozlesmeye uyan alt sinif: agirlikla artan bir sigorta payi ekler
import { Tarife } from "./tarife.mjs";

export class SigortaliTarife extends Tarife {
  #gramBasi;
  constructor(ayar, gramBasi) { super(ayar); this.#gramBasi = gramBasi; }
  ucret(agirlik, bolge) {
    return super.ucret(agirlik, bolge) + Math.round(agirlik * this.#gramBasi);
  }
}
```

İkincisi elden teslim tarifesidir. Talep gerçektir: 6 ile 9 kilogram arasındaki gönderiler
tek kişiyle taşınamadığı için ek ücretlendirilir. Gerçekleştirim de doğrudan görünür.

```js
// elden-teslim.mjs — sozlesmeyi ciyneyen alt sinif: bir agirlik bandina ek ucret koyar
import { Tarife } from "./tarife.mjs";

export class EldenTeslimTarifesi extends Tarife {
  #bandaEk;
  constructor(ayar, bandaEk) { super(ayar); this.#bandaEk = bandaEk; }
  ucret(agirlik, bolge) {
    const taban = super.ucret(agirlik, bolge);
    return agirlik >= 6000 && agirlik <= 9000 ? taban + this.#bandaEk : taban;
  }
}
```

İki sınıf da aynı biçimde yazılmıştır: aynı üst sınıf, aynı yöntem imzası, aynı dönüş tipi.
Aralarındaki fark bandın **çıkışındadır**: 9000 gramda ücret ek yükle birlikte yüksektir,
9001 gramda ek kalkar ve ücret düşer. S3 maddesi çiğnenmiştir.

Gerçekleştirim paylaşımı vaadi ikisinde de tutuldu. Ölçüsü satır sayısıdır.

```sh
for f in tarife.mjs sigortali.mjs elden-teslim.mjs; do echo "$f  $(grep -c . $f) satir"; done
```

```
tarife.mjs  27 satir
sigortali.mjs  9 satir
elden-teslim.mjs  10 satir
```

Yirmi yedi satırlık kademe, katsayı ve asgari ücret mantığı iki alt sınıfın hiçbirinde
tekrar edilmedi; ikisi de dokuz–on satırla yetindi. Kalıtımın birinci vaadi bakımından iki
alt sınıf arasında hiçbir fark yok. Fark yalnız ikinci vaatte.

## Sözleşme Denetleyicisi

Üç madde bir ağırlık ızgarası üzerinde denenir. Denetleyici üst tipe bağımlıdır; hangi alt
sınıfın verildiğini bilmez.

```js
// sozlesme.mjs — ucret sozlesmesinin uc maddesini bir agirlik izgarasinda dener
export function ihlaller(tarife) {
  const kirik = new Set();
  for (const bolge of tarife.bolgeler()) {
    let onceki = -Infinity;
    for (let a = 100; a <= 20000; a += 100) {
      let u;
      try { u = tarife.ucret(a, bolge); } catch { kirik.add("S1 her gecerli girdide tanimli"); continue; }
      if (!Number.isFinite(u)) kirik.add("S1 her gecerli girdide tanimli");
      if (u < tarife.asgari) kirik.add("S2 asgari ucretin altina inmez");
      if (u < onceki) kirik.add("S3 agirlikla azalmaz");
      onceki = u;
    }
  }
  return [...kirik].sort();
}
```

## Üst Tip Üzerinden Çalışan İstemci

İstemci, verilen bütçeyle gönderilebilecek en ağır gönderiyi bulur. İkili arama kullanır ve
bu seçim doğrudan S3 maddesine dayanır: bir ağırlıkta ücret bütçeyi aşıyorsa, daha ağır
hiçbir gönderi bütçeye girmez. Aynı dosya, doğruluk ölçütü olarak tek tek tarayan yavaş bir
sürümü de içerir.

```js
// butce.mjs — istemci: verilen butceyle gonderilebilecek en agir gonderiyi bulur
const UST = 16000;

export function ikiliArama(tarife, bolge, butce) {
  let alt = 0, ust = UST;
  while (alt < ust) {
    const orta = Math.ceil((alt + ust) / 2);
    if (tarife.ucret(orta, bolge) <= butce) alt = orta; else ust = orta - 1;
  }
  return alt;
}

export function tarama(tarife, bolge, butce) {
  let en = 0;
  for (let a = 0; a <= UST; a += 1) if (tarife.ucret(a, bolge) <= butce) en = a;
  return en;
}
```

Koşum, iki alt sınıfı önce sözleşme denetiminden, sonra üç bölge ve altmış bütçe üzerinde
istemciden geçirir.

```js
// kosum.mjs — iki alt sinifi ayni sozlesme denetiminden ve ayni istemciden gecirir
import { AYAR } from "./tarife.mjs";
import { SigortaliTarife } from "./sigortali.mjs";
import { EldenTeslimTarifesi } from "./elden-teslim.mjs";
import { ihlaller } from "./sozlesme.mjs";
import { ikiliArama, tarama } from "./butce.mjs";

const BUTCELER = Array.from({ length: 60 }, (_, i) => 5000 + i * 500);

for (const [ad, tarife] of [
  ["SigortaliTarife", new SigortaliTarife(AYAR, 0.2)],
  ["EldenTeslimTarifesi", new EldenTeslimTarifesi(AYAR, 8000)],
]) {
  const kirik = ihlaller(tarife);
  let yanlis = 0;
  let enBuyukFark = 0;
  for (const bolge of tarife.bolgeler()) {
    for (const butce of BUTCELER) {
      const bulunan = ikiliArama(tarife, bolge, butce);
      const dogru = tarama(tarife, bolge, butce);
      if (bulunan !== dogru) { yanlis += 1; enBuyukFark = Math.max(enBuyukFark, dogru - bulunan); }
    }
  }
  console.log(`${ad}`);
  console.log(`  sozlesme ihlali    = ${kirik.length}  ${kirik.join("; ")}`);
  console.log(`  yanlis sonuc       = ${yanlis}/${BUTCELER.length * 3}`);
  console.log(`  en buyuk sapma     = ${enBuyukFark} gram`);
}
```

```sh
node kosum.mjs
```

```
SigortaliTarife
  sozlesme ihlali    = 0
  yanlis sonuc       = 0/180
  en buyuk sapma     = 0 gram
EldenTeslimTarifesi
  sozlesme ihlali    = 1  S3 agirlikla azalmaz
  yanlis sonuc       = 48/180
  en buyuk sapma     = 8001 gram
```

Elden teslim tarifesiyle 180 sorgunun 48'i yanlış yanıtlandı. En büyük sapmada istemci,
bütçenin gerçekte 8001 gram daha ağır bir gönderiyi karşıladığı durumda daha hafif bir
gönderi önerdi. İstemcinin kodunda hata yok; ikili arama S3 maddesi geçerliyken doğrudur.
Hata, sözleşmeyi çiğneyen alt sınıfın üst tip yerine konmasıyla ortaya çıktı.

Sayının 180'in tamamı olmaması da bilgi taşıyor. İhlal, ancak aramanın bir yoklaması ek
ücret bandına düştüğünde görünür oluyor; diğer sorgularda program doğru yanıt veriyor.
Sözleşme ihlalleri her çağrıda değil, belirli girdi bölgelerinde patlar; bu yüzden örnek
girdilerle yapılan sınamalarda gözden kaçar.

## Sözleşme Nerede Yazılı

Elden teslim tarifesi hiçbir tip denetiminden geçmez değildir; tam tersine her denetimden
geçer. Yöntem imzası aynı, dönüş tipi aynı, `extends` bağı geçerli. Statik tipleme S1'in bir
bölümünü — parametre ve dönüş tiplerini — yakalar; S2 ve S3'ü yakalamaz, çünkü bunlar
tiplerin değil değerlerin ilişkisidir.

Ölçülen 48 yanlış sonuç, sözleşmenin yazılı olmamasının bedelidir. Üç maddenin metne
dökülmesi ve `sozlesme.mjs` gibi bir denetleyiciyle her alt sınıfa uygulanması, bu bedeli
istemcinin çalışma zamanından alt sınıfın yazıldığı ana taşır. Aynı denetleyici ihlali
tek satırda gösterdi.

Elden teslim ihtiyacının kendisi yanlış değildi; onu bir alt sınıf olarak modellemek
yanlıştı. Bant ücreti tarifenin bir alt türü değil, tarifeye eklenen ayrı bir hizmet
kalemidir; ücretin yanında ayrı bir alan olarak taşınırsa S3 çiğnenmez.

## Özet

- Kalıtım iki ayrı şey vaat eder: gerçekleştirim paylaşımı ve alt tip ilişkisi; `extends`
  birincisini kesin olarak sağlar, ikincisini hiç sağlamayabilir.
- Gerçekleştirim paylaşımı iki alt sınıfta da tutuldu: 27 satırlık üst sınıf mantığı dokuz
  ve on satırlık alt sınıflarda tekrar edilmedi.
- Alt tip ilişkisi ancak üst tipin sözleşmesi yazılıysa denetlenebilir; buradaki sözleşme üç
  maddeydi ve üçüncüsü koddan okunamıyordu.
- Sözleşmeye uyan alt sınıf 0 ihlal ve 180 sorguda 0 yanlış sonuç verdi; uymayan alt sınıf
  1 ihlal ve 48 yanlış sonuç verdi, en büyük sapma 8001 gramdı.
- İhlal her çağrıda değil belirli girdi bölgelerinde görünür; örnek girdilerle yapılan
  sınamada 180 sorgunun 132'si doğru yanıt verdi.
- Statik tipleme yalnız imza uyumunu denetler; sonucun değerine ilişkin maddeler yazılı bir
  sözleşme ve onu uygulayan bir denetleyici gerektirir.

## Sonraki Adım

Bu derste iki alt sınıf da aynı adla — `ucret` — farklı davrandı ve istemci hangisiyle
çalıştığını bilmedi. Bu, tek bir adın birden çok davranışa karşılık gelmesidir ve alt tip
ilişkisi bunun yalnız bir yoludur. Sonraki ders üç yolu da kurar: alt tip, parametrik ve
geçici çok biçimlilik. Ölçüm de değişir — aynı problem üç yolla gerçekleştirilir, sonra
sisteme yeni bir tarife türü ve yeni bir işlem eklenir ve her yolda dokunulan dosya sayısı
sayılır.
