---
title: 'Kimlik Haritası'
source: 'https://academia.sh/tr/kurslar/tasarim-kaliplari/kimlik-haritasi'
course: 'Tasarım Kalıpları'
language: tr
updated: '2026-08-17T18:10:39+00:00'
license: 'CC BY-SA 4.0'
---

# Kimlik Haritası

Aynı kimliğin tek nesneyle temsil edilmesi: haritasız ve haritalı koşumda üretilen ayrı örnek sayısının, iki kod yolunun aynı kaydı değiştirmesiyle kaybolan alan sayısının ve haritanın bellekte tuttuğu nesne sayısının ölçülmesi, haritanın yaşam süresi uzadığında ortaya çıkan bayat okumanın gösterilmesi.

İş birimi kirli satırları `tablo:kimlik` anahtarıyla topladı ve aynı satır üç kez kirlense de
bir kez yazıldı. Bu, yazma tarafında çözülmüş bir tekillik sorunudur. Okuma tarafında aynı
sorun açık duruyor: aynı gönderi kimliği iki kez arandığında iki ayrı nesne doğar. Bir kod
yolu birinci nesnenin indirimini değiştirir, ikinci kod yolu ikinci nesnenin rotasına aktarma
ekler; ikisi de kaydedildiğinde son yazan öteki değişikliği siler.

**Kimlik haritası** (identity map) bu soruna tek cümlelik bir çözüm koyar: bir kimlik için
üretilen nesne saklanır, aynı kimlik yeniden arandığında yeni nesne üretilmez, saklanan
döndürülür. Kalıp Veri Erişim Katmanı kursunda üretilen sorgu sayısı üzerinden ölçülmüştü.
Burada ölçü nesne düzeyindedir: kaç ayrı örnek doğdu, kaç alan kayboldu, harita bellekte kaç
nesne tuttu.

## Problem: Aynı Kimlik, İki Nesne

Deponun okuma davranışı sorunun kaynağıdır. Bir depo satırın kendisini değil kopyasını verir;
aksi hâlde çağıran taraf saklanan satırı doğrudan değiştirebilirdi.

```js
// bellek-depo.mjs — her okumada satirin yeni bir kopyasini veren sade depo
const TABLOLAR = new Map();
const tablo = (ad) => TABLOLAR.get(ad) ?? TABLOLAR.set(ad, new Map()).get(ad);

export const depo = {
  oku: (ad, id) => structuredClone(tablo(ad).get(id) ?? null),
  yaz: (ad, satir) => { tablo(ad).set(satir.id, structuredClone(satir)); },
};
```

```js
// gonderi.mjs — kimligi olan alan nesnesi
export class Gonderi {
  constructor({ id, agirlik, indirim, aktarma }) {
    Object.assign(this, { id, agirlik, indirim, aktarma });
  }
  net() { return Math.round(3900 * this.agirlik * (1 - this.indirim)); }
}
```

Kopya vermek doğru karardır ama bir yan sonucu vardır: iki arama iki bağımsız nesne üretir ve
ikisi de aynı kaydı temsil ettiğini bilmez.

## Çözüm

Harita, üretim işini kendi içine alır. Nesnenin nasıl üretileceğini bilmez; yalnız daha önce
üretilip üretilmediğini bilir.

```js
// kimlik-haritasi.mjs — istek boyunca kimlik basina tek nesne
export function kimlikHaritasi() {
  const harita = new Map();
  return {
    al(tur, id, uret) {
      const anahtar = `${tur}:${id}`;
      if (harita.has(anahtar)) return harita.get(anahtar);
      const nesne = uret();
      harita.set(anahtar, nesne);
      return nesne;
    },
    tutulan: () => harita.size,
  };
}
```

Anahtarın tür adını da içermesi zorunludur: iki ayrı türün aynı kimliği taşıması sıradan bir
durumdur. Erişim noktası tek bir yerde kalır.

```js
// kaynak.mjs — ayni esleyici; harita verilirse ayni kimlik ayni nesneyi dondurur
import { depo } from "./bellek-depo.mjs";
import { Gonderi } from "./gonderi.mjs";

export const kaynak = (harita) => ({
  bul(id) {
    const uret = () => {
      const satir = depo.oku("gonderi", id);
      return satir === null ? null : new Gonderi(satir);
    };
    return harita === null ? uret() : harita.al("gonderi", id, uret);
  },
  kaydet: (g) => depo.yaz("gonderi", { id: g.id, agirlik: g.agirlik, indirim: g.indirim, aktarma: g.aktarma }),
});
```

## Tekilliğin Sayılması

Ölçüm iki koşum yapar. Beş arama üç ayrı kimliğe gider; ardından aynı kimlik iki kez aranır,
iki kod yolu ayrı alanları değiştirir ve ikisi de kaydedilir.

```js
// tekillik-say.mjs — haritasiz ve haritali kosumda ayri ornek, kayip alan ve tutulan nesne
import { depo } from "./bellek-depo.mjs";
import { kaynak } from "./kaynak.mjs";
import { kimlikHaritasi } from "./kimlik-haritasi.mjs";

const KIMLIKLER = ["G1", "G2", "G3"];
const ARAMALAR = ["G1", "G2", "G3", "G2", "G1"];

function kosu(ad, harita) {
  for (const id of KIMLIKLER) depo.yaz("gonderi", { id, agirlik: 3, indirim: 0, aktarma: ["34"] });
  const k = kaynak(harita);
  const ornekler = new Set(ARAMALAR.map((id) => k.bul(id)));

  const ucret = k.bul("G2"), yon = k.bul("G2");
  ucret.indirim = 0.15;
  yon.aktarma.push("06");
  k.kaydet(ucret);
  k.kaydet(yon);

  const son = depo.oku("gonderi", "G2");
  const beklenen = { indirim: 0.15, aktarma: 2 };
  const kayip = (son.indirim === beklenen.indirim ? 0 : 1) + (son.aktarma.length === beklenen.aktarma ? 0 : 1);
  console.log(`${ad}`);
  console.log(`  ${ARAMALAR.length} arama -> ayri ornek = ${ornekler.size}   ayni kimlik ayni nesne mi = ${ucret === yon}`);
  console.log(`  yazma sonrasi indirim = ${son.indirim}, aktarma = ${son.aktarma.length}, kayip alan = ${kayip}`);
  console.log(`  haritada tutulan nesne = ${harita === null ? 0 : harita.tutulan()}`);
}

kosu("haritasiz", null);
kosu("kimlik haritasi ile", kimlikHaritasi());
```

```sh
node tekillik-say.mjs
```

```
haritasiz
  5 arama -> ayri ornek = 5   ayni kimlik ayni nesne mi = false
  yazma sonrasi indirim = 0, aktarma = 2, kayip alan = 1
  haritada tutulan nesne = 0
kimlik haritasi ile
  5 arama -> ayri ornek = 3   ayni kimlik ayni nesne mi = true
  yazma sonrasi indirim = 0.15, aktarma = 2, kayip alan = 0
  haritada tutulan nesne = 3
```

Beş arama haritasız düzende 5 ayrı nesne üretti, haritalı düzende 3 — kimlik sayısı kadar.
Aynı kimliği iki kez arayan iki kod yolu haritasız düzende iki farklı nesne aldı ve `===`
karşılaştırması yanlış sonuç verdi; harita ile aynı nesneyi aldılar.

Kayıp alan sayısı farkın en somut biçimidir: haritasız koşumda indirim değişikliği kayboldu,
kaydedilen satırda indirim 0 kaldı. Haritalı koşumda iki değişiklik de aynı nesnenin üzerinde
birikti ve ikisi birlikte yazıldı.

Karşılıkta bir sayı daha var: harita 3 nesneyi bellekte tutuyor. Haritasız düzende tutulan
nesne 0'dır, üretilen nesneler kullanıldıktan sonra bırakılır. Kalıbın bedeli tam olarak
budur ve ikinci bir sonuç doğurur.

## Haritanın Yaşam Süresi

Harita bir nesneyi tuttuğu sürece o nesne deponun sonraki hâlini görmez.

```js
// bayat.mjs — harita yasarken depo degisirse okunan deger hangisi olur
import { depo } from "./bellek-depo.mjs";
import { kaynak } from "./kaynak.mjs";
import { kimlikHaritasi } from "./kimlik-haritasi.mjs";

for (const [ad, harita] of [["haritasiz", null], ["kimlik haritasi ile", kimlikHaritasi()]]) {
  depo.yaz("gonderi", { id: "G9", agirlik: 3, indirim: 0.1, aktarma: ["34"] });
  const k = kaynak(harita);
  const ilk = k.bul("G9").indirim;
  depo.yaz("gonderi", { id: "G9", agirlik: 3, indirim: 0.3, aktarma: ["34"] });
  const ikinci = k.bul("G9").indirim;
  console.log(`${ad.padEnd(20)} ilk okuma = ${ilk}, depo 0.3 oldu, ikinci okuma = ${ikinci}, bayat = ${ikinci !== 0.3}`);
}
```

```sh
node bayat.mjs
```

```
haritasiz            ilk okuma = 0.1, depo 0.3 oldu, ikinci okuma = 0.3, bayat = false
kimlik haritasi ile  ilk okuma = 0.1, depo 0.3 oldu, ikinci okuma = 0.1, bayat = true
```

İkinci okuma haritasız düzende yeni değeri, haritalı düzende ilk değeri verdi. Bu bir kusur
değil, kalıbın tanımının gereğidir: harita bir nesnenin tekilliğini garanti eder, tazeliğini
garanti etmez. Buradan kalıbın uygulanma sınırı çıkar. Harita bir işin — tek bir isteğin ya
da tek bir iş biriminin — sınırında yaşar ve o sınır bittiğinde bırakılır. Süreç boyunca
yaşayan bir harita bir önbelleğe dönüşür ve tazelik sorusu sorulmaya başlar; o soru kimlik
haritasının cevapladığı soru değildir.

## Ne Zaman Uygulanmaz

Kalıbın kazancı iki koşuldan doğar: nesnenin bir kimliği olması ve değiştirilebilir olması.
İkisinden biri yoksa kazanç sıfırlanır.

Değer nesnelerinde kimlik yoktur; iki bölge katsayısı aynı değeri taşıyorsa birbirinin yerine
geçer ve eşitlik değere göre kurulur. Değiştirilemez bir değer nesnesinde iki ayrı örneğin
birbirini ezmesi de olanaksızdır, dolayısıyla ölçümdeki kayıp alan sayısı harita olmadan da
0'dır. Kazanç 0, bedel ise haritanın tuttuğu nesne sayısı kadar.

Tek okuma yapan senaryolarda da kazanç yoktur: ayrı örnek sayısı zaten arama sayısına eşittir
ve arama sayısı 1'dir. Son sınır ölçekle ilgilidir. Harita süreç yereldir; iki ayrı süreç aynı
kaydı yüklerse her birinin haritası kendi nesnesini tutar ve tekillik süreçler arasında
korunmaz. Süreçler arası aynı anda yazma sorunu kilitleme konusuna aittir ve Veri Erişim
Katmanı kursunda ölçülmüştür.

## Özet

- Kimlik haritası bir kimlik için üretilen nesneyi saklar ve aynı kimlik yeniden arandığında
  yeni nesne üretmek yerine saklananı döndürür.
- Beş arama haritasız düzende 5 ayrı örnek, haritalı düzende kimlik sayısı kadar 3 örnek
  üretti; aynı kimliği arayan iki kod yolu haritasız düzende `===` karşılaştırmasını
  geçemedi.
- İki kod yolu aynı kaydın ayrı alanlarını değiştirdiğinde haritasız koşumda 1 alan kayboldu;
  haritalı koşumda iki değişiklik aynı nesnede birikti ve kayıp 0 oldu.
- Bedel bellekte tutulan nesne sayısıdır (3'e karşı 0) ve ikinci bedel bayat okumadır: depo
  değiştiğinde haritalı düzen ilk değeri vermeye devam etti.
- Harita tek bir işin sınırında yaşar; değer nesnelerinde ve tek okumalı senaryolarda kazanç
  sıfırlanır, süreçler arasında tekillik korunmaz.

## Sonraki Adım

Buraya kadarki dört kalıp iş mantığı ile kalıcılık arasındaki sınırı düzenledi. Alan nesnesi
artık kuralı taşıyor, kalıcılığı bilmiyor ve bellekte tekil. Ama bu nesne kitaplığın dışına da
çıkacak: bir arayüz onu listeleyecek, bir taşıyıcı sistemi ona rota soracak, bir fatura
dökümü ondan üretilecek. Alan nesnesinin dışarıya olduğu gibi verilmesi iç yapıyı dış
sözleşme hâline getirir ve iç yapı her değiştiğinde dış sözleşme de değişir. Sonraki ders
katmanlar arası veri taşımayı veri aktarım nesneleri ve eşleyicilerle kurar, iç modelde bir
alan yeniden adlandırıldığında dokunulan dosya sayısını ve eşlemenin satır başına bedelini
sayar.
