---
title: 'Bileşim Kalıtıma Tercih Edilir'
source: 'https://academia.sh/tr/kurslar/paradigmalar/bilesim-kalitima-tercih-edilir'
course: 'Programlama Paradigmaları'
language: tr
updated: '2026-08-17T18:10:41+00:00'
license: 'CC BY-SA 4.0'
---

# Bileşim Kalıtıma Tercih Edilir

Kırılgan üst sınıf sorununun ölçülmesi: üst sınıfta kendi davranışını değiştirmeyen bir gerçekleştirim değişikliğinin alt sınıfın sayacını 200 nesnenin 200'ünde sessizce bozması, aynı değişikliğin bileşimli sürümde hiçbir sapma üretmemesi ve bileşimin iletme bedelinin sayılması.

Önceki ders ortak davranışın iki yolla paylaşılabildiğini gösterdi: kalıtımla ve nesneyi
argüman alan işlevlerle. Ölçüm o noktada tekrar edilen satır sayısıydı. Aynı tercihin bir
başka sonucu daha vardır ve bu, üst sınıf kendi içinde bir değişiklik yaptığında ortaya
çıkar. Alt sınıf, üst sınıfın **dışarıya söylediklerine** değil, içeride ne yaptığına da
bağımlı olabilir.

**Kırılgan üst sınıf sorunu** (fragile base class problem), üst sınıfta yapılan ve üst
sınıfın kendi davranışını değiştirmeyen bir gerçekleştirim değişikliğinin alt sınıfların
davranışını bozmasıdır. Bu ders sorunu ölçer, sonra aynı değişikliği bileşimli bir sürümde
dener.

## Sevkiyat ve İki Sarmalama Yolu

Üst sınıf, kapsülleme dersindeki sevkiyat sınıfının sadeleştirilmiş bir sürümüdür: kapasiteyi
aşmayan gönderileri kabul eder, aşanları reddeder. `hepsiniEkle` yöntemi bir partiyi tek tek
`ekle` yöntemine verir.

```js
// sevkiyat.mjs — ust sinif, ilk surum: hepsiniEkle her ogeyi kendi ekle yontemiyle isler
export class Sevkiyat {
  #gonderiler = []; #toplam = 0; #kapasite;

  constructor(kapasiteGram) { this.#kapasite = kapasiteGram; }

  ekle(gonderi) {
    if (this.#toplam + gonderi.agirlikGram > this.#kapasite) return false;
    this.#gonderiler.push(gonderi);
    this.#toplam += gonderi.agirlikGram;
    return true;
  }

  hepsiniEkle(gonderiler) { for (const g of gonderiler) this.ekle(g); }

  durum() { return { adet: this.#gonderiler.length, toplam: this.#toplam }; }
}
```

Yeni bir ihtiyaç doğar: kabul edilen gönderilerin sayılması. Birinci karşılık kalıtımdır.
Alt sınıf `ekle` yöntemini kendi gerçekleştirimiyle karşılar, üst sürümü çağırır ve kabulleri
sayar.

```js
// sayan-kalitim.mjs — kalitimla sarmalama: alt sinif ekle yontemini kendi surumuyle karsilar
import { Sevkiyat } from "./sevkiyat.mjs";

export class SayanSevkiyat extends Sevkiyat {
  #sayac = 0;
  get sayac() { return this.#sayac; }
  ekle(gonderi) {
    const kabul = super.ekle(gonderi);
    if (kabul) this.#sayac += 1;
    return kabul;
  }
}
```

İkinci karşılık bileşimdir. Sarmalayıcı sevkiyatı içeride tutar, dışarıya aynı yöntemleri
sunar ve `hepsiniEkle` yöntemini kendi `ekle` yöntemi üzerinden yazar.

```js
// sayan-bilesim.mjs — bilesimle sarmalama: sevkiyat iceride tutulur, yontemler iletilir
export class SayanSarmalayici {
  #ic; #sayac = 0;

  constructor(sevkiyat) { this.#ic = sevkiyat; }

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

  ekle(gonderi) {
    const kabul = this.#ic.ekle(gonderi);
    if (kabul) this.#sayac += 1;
    return kabul;
  }

  hepsiniEkle(gonderiler) { for (const g of gonderiler) this.ekle(g); }

  durum() { return this.#ic.durum(); }
}
```

İki sürüm dışarıdan ayırt edilemez. Koşum, sabit tohumlu bir üreteçle 200 parti üretir, her
partiyi iki sarmalayıcıya da verir ve sayaçları bağımsız hesaplanan doğru değerle
karşılaştırır.

```js
// kosum.mjs — ayni parti dizisini iki sarmalama yoluna uygular ve sayaclari dogrular
import { Sevkiyat } from "./sevkiyat.mjs";
import { SayanSevkiyat } from "./sayan-kalitim.mjs";
import { SayanSarmalayici } from "./sayan-bilesim.mjs";

const uretec = (tohum) => {
  let x = tohum;
  return () => (x = (x * 1103515245 + 12345) % 2147483648) / 2147483648;
};

const NESNE = 200;
const KAPASITE = 20000;

const partiler = () => {
  const rast = uretec(20250729);
  return Array.from({ length: NESNE }, () =>
    Array.from({ length: 12 }, (_, i) => ({ id: i, agirlikGram: 500 + Math.floor(rast() * 3500) })));
};

const dogruSayi = (parti) => {
  let toplam = 0, adet = 0;
  for (const g of parti) if (toplam + g.agirlikGram <= KAPASITE) { toplam += g.agirlikGram; adet += 1; }
  return adet;
};

let kalitimYanlis = 0, bilesimYanlis = 0;
const veri = partiler();
for (const parti of veri) {
  const dogru = dogruSayi(parti);
  const k = new SayanSevkiyat(KAPASITE); k.hepsiniEkle(parti);
  const b = new SayanSarmalayici(new Sevkiyat(KAPASITE)); b.hepsiniEkle(parti);
  if (k.sayac !== dogru) kalitimYanlis += 1;
  if (b.sayac !== dogru) bilesimYanlis += 1;
}

const temiz = new Sevkiyat(KAPASITE);
temiz.hepsiniEkle(veri[0]);
const d = temiz.durum();
console.log(`ust sinifin kendi davranisi = adet ${d.adet}, toplam ${d.toplam}`);
console.log(`kalitimli sayac yanlis      = ${kalitimYanlis}/${NESNE}`);
console.log(`bilesimli sayac yanlis      = ${bilesimYanlis}/${NESNE}`);
const yeni = (n) => (typeof n.muhurle === "function" ? "var" : "yok");
console.log(`yeni ust sinif yontemi      = kalitim ${yeni(new SayanSevkiyat(KAPASITE))},` +
  ` bilesim ${yeni(new SayanSarmalayici(new Sevkiyat(KAPASITE)))}`);
```

```sh
node kosum.mjs
```

```
ust sinifin kendi davranisi = adet 9, toplam 18566
kalitimli sayac yanlis      = 0/200
bilesimli sayac yanlis      = 0/200
yeni ust sinif yontemi      = kalitim yok, bilesim yok
```

İki yol da doğru sayıyor. Bu noktada aralarında seçim yapmak için bir gerekçe görünmüyor.

## Üst Sınıfta Bir Değişiklik

Üst sınıfın bakımını üstlenen taraf `hepsiniEkle` yöntemini yeniden yazar: her öge için
yöntem çağrısı yapmak yerine döngüyü kendi içinde çalıştırır. Aynı sürümde bir de yeni bir
yöntem eklenir — sevkiyatın kapasitesini o anki toplama sabitleyen `muhurle`.

```js
// sevkiyat-v2.mjs — ust sinifin ikinci surumu: hepsiniEkle ic dongusunu kendi icinde yapar
export class Sevkiyat {
  #gonderiler = []; #toplam = 0; #kapasite;

  constructor(kapasiteGram) { this.#kapasite = kapasiteGram; }

  ekle(gonderi) {
    if (this.#toplam + gonderi.agirlikGram > this.#kapasite) return false;
    this.#gonderiler.push(gonderi);
    this.#toplam += gonderi.agirlikGram;
    return true;
  }

  hepsiniEkle(gonderiler) {
    for (const g of gonderiler) {
      if (this.#toplam + g.agirlikGram > this.#kapasite) continue;
      this.#gonderiler.push(g);
      this.#toplam += g.agirlikGram;
    }
  }

  muhurle() { this.#kapasite = this.#toplam; }

  durum() { return { adet: this.#gonderiler.length, toplam: this.#toplam }; }
}
```

Değişiklik üst sınıfın **kendi** davranışını korur: aynı gönderiler kabul edilir, aynı
gönderiler reddedilir, aynı toplam çıkar. Aynı koşum yeni sürümle tekrarlanır.

```sh
cp sevkiyat-v2.mjs sevkiyat.mjs
node kosum.mjs
```

```
ust sinifin kendi davranisi = adet 9, toplam 18566
kalitimli sayac yanlis      = 200/200
bilesimli sayac yanlis      = 0/200
yeni ust sinif yontemi      = kalitim var, bilesim yok
```

Üst sınıfın kendi davranışı birinci satırda birebir aynı: 9 gönderi, 18566 gram. Üst sınıf
için yazılmış her sınama iki sürümde de geçerdi. Alt sınıfın sayacı ise 200 nesnenin
200'ünde yanlışa döndü. Hiçbir istisna fırlamadı, hiçbir uyarı çıkmadı; sayaç sıfırda kaldı.

## Sapmanın Kaynağı

Alt sınıfın sayacı, üst sınıfın `hepsiniEkle` yöntemi içinde `this.ekle` çağırmasına
bağlıydı. Bu çağrı üst sınıfın belgelenmiş sözleşmesinin parçası değildi; bir gerçekleştirim
ayrıntısıydı. Alt sınıf o ayrıntıya, farkında olmadan, bir bağımlılık kurdu.

Buradaki asıl gözlem şudur: kalıtım, üst sınıfın **iç çağrı örüntüsünü** de sözleşmenin
parçası hâline getirir. Bir üst sınıfın alt sınıflara verdiği güvence yalnız "hangi
yöntemler var, ne döndürürler" değildir; "hangi yöntem hangisini çağırır" da güvencenin
içine girer. Bu ikinci bölüm neredeyse hiçbir zaman yazılmaz ve yazılmadığı için de
korunmaz.

Bileşimli sarmalayıcı bu bağımlılığı hiç kurmadı. Onun `hepsiniEkle` yöntemi kendi `ekle`
yöntemini çağırıyordu; iç nesnenin `hepsiniEkle` yöntemini hiç kullanmadı. İç nesneden
istediği tek şey, açıkça çağırdığı `ekle` ve `durum` yöntemlerinin davranışıydı — yani
belgelenmiş sözleşme. Üst sınıfın iç düzenlemesi değiştiğinde etkilenmemesinin nedeni budur.

## Bileşimin Bedeli

Son satır bileşimin bedelini gösteriyor. Yeni sürümde eklenen `muhurle` yöntemi kalıtımlı
sürümde kendiliğinden ortaya çıktı, bileşimli sürümde çıkmadı. Sarmalayıcı, iç nesnenin
kazandığı hiçbir yeteneği bedava almaz.

Bedelin ikinci yüzü iletme kodudur. Sarmalayıcı üç yöntemi elle yazdı: `ekle`, `hepsiniEkle`
ve `durum`. İç sınıfın arayüzü on yönteme çıksaydı, sarmalayıcının dışarıya aynı yüzü
sunabilmesi için on iletme yazılması gerekirdi. Kalıtımda bu sayı sıfırdır.

İki bedel karşılaştırılabilir. Kalıtımın bedeli, üst sınıf her değiştiğinde ortaya çıkabilen
ve ölçümde 200/200 olarak görünen sessiz sapmadır. Bileşimin bedeli, arayüz her
genişlediğinde yazılması gereken ve derhâl görünen iletme kodudur. İkincisi sayılabilir ve
öngörülebilir; birincisi ne sayılabilir ne öngörülebilir. Tercihin gerekçesi budur.

## Kalıtımın Ucuz Kaldığı Durum

Kalıtım her durumda pahalı değildir. Üst sınıf ile alt sınıf aynı ekip tarafından ve aynı
sürümle bakılıyorsa, üst sınıfın iç çağrı örüntüsü değiştiğinde alt sınıflar da gözden
geçirilebilir; sapma sessiz kalmaz. Aynı biçimde, üst sınıf değişmeye kapalıysa — sürümü
sabitlenmiş, davranışı dondurulmuş bir tipse — kırılganlık zemini ortadan kalkar.

Kırılganlık, üst sınıfın alt sınıflardan bağımsız olarak değiştiği durumlarda doğar: farklı
bir ekip, farklı bir sürüm hattı, farklı bir depo. Ölçüt sınıf sayısı ya da hiyerarşi
derinliği değil, **kimin ne zaman değiştirdiğidir**.

## Özet

- Kırılgan üst sınıf sorunu, üst sınıfın kendi davranışını korumasına rağmen alt sınıfları
  bozan bir gerçekleştirim değişikliğidir.
- Ölçümde üst sınıfın kendi davranışı iki sürümde birebir aynı kaldı (9 gönderi, 18566 gram);
  buna rağmen kalıtımlı sayaç 200 nesnenin 200'ünde yanlışa döndü.
- Aynı değişiklik bileşimli sarmalayıcıda 0 sapma üretti; sarmalayıcı iç nesneden yalnız
  açıkça çağırdığı yöntemlerin davranışına bağımlıydı.
- Kalıtım, üst sınıfın iç çağrı örüntüsünü de sözleşmenin parçası yapar; bu bölüm neredeyse
  hiç yazılmadığı için korunmaz.
- Bileşimin bedeli iletme kodudur ve sayılabilir: sarmalayıcı burada üç yöntem iletti;
  ayrıca üst sınıfa eklenen yeni yöntem bileşimli sürümde kendiliğinden görünmedi.
- Kalıtım, üst sınıfla alt sınıfın birlikte bakıldığı ya da üst sınıfın değişime kapalı
  olduğu durumlarda ucuz kalır; ölçüt kimin ne zaman değiştirdiğidir.

## Sonraki Adım

Bu ders iki nesnenin birbirine nasıl bağlanacağını ölçtü. Bir sonraki soru bir nesnenin
kendi içinde ne taşıyacağıdır. Sevkiyat sınıfı hem gönderileri hem kapasite kuralını
tutuyordu; kural veriyle aynı yerdeydi. Yaygın bir başka düzen bunu ayırır: veri yalnız
alan taşır, kurallar ayrı işlemci birimlerine dağılır. Sonraki ders iki düzeni karşılaştırır
ve bir kuralın kaç ayrı yerde tekrarlandığını sayar; sonra kural değiştirildiğinde her iki
düzende kaç sonucun birbirinden ayrıldığını ölçer.
