---
title: 'Veri Aktarım Nesneleri ve Eşleyiciler'
source: 'https://academia.sh/tr/kurslar/tasarim-kaliplari/veri-aktarim-nesneleri-ve-esleyiciler'
course: 'Tasarım Kalıpları'
language: tr
updated: '2026-08-17T18:10:39+00:00'
license: 'CC BY-SA 4.0'
---

# Veri Aktarım Nesneleri ve Eşleyiciler

Katmanlar arası veri taşımanın kalıp düzeyinde ele alınması: iç modelin biçimi değiştiğinde doğrudan okuyan istemcilerin bozulmasıyla eşleyici arkasındaki istemcilerin bozulmamasının sayılması, istemci kodundaki iç alan adı sayısı ve eşlemenin alan başına satır bedeli.

Buraya kadarki dört kalıp iş mantığı ile kalıcılık arasındaki sınırı düzenledi. Alan nesnesi
kuralı taşıyor, kalıcılığı bilmiyor ve bellekte tekil. Bu nesne kitaplığın dışına da çıkacak:
bir arayüz onu listeleyecek, bir fatura dökümü ondan üretilecek, bir kütük satırı onu
kaydedecek. Nesnenin dışarıya olduğu gibi verilmesi iç yapıyı dış sözleşme hâline getirir.

**Veri aktarım nesnesi** (data transfer object) bu sözleşmeyi ayrı bir düz kayıt olarak
tanımlar; **eşleyici** iç modelden o kaydı üretir. Kalıp Veri Erişim Katmanı kursunda
kurulmuş ve orada dış sözleşmeye sızan alan sayısıyla ölçülmüştü. Burada ölçü değişim
tarafındadır: iç modelin biçimi değiştiğinde kaç istemci çıktısı bozuluyor, istemci kodu kaç
iç alan adı taşıyor, eşleme alan başına kaç satıra mal oluyor.

## Problem: İç Biçim Dışarıdan Okunursa

İç model aynı bilgiyi iki farklı biçimde tutabilir. İkinci sürümde ücretle ilgili alanlar iç
içe bir nesneye taşınmış durumda; taşınan bilgi aynı, adres farklı.

```js
// alan.mjs — ayni bilginin iki ic modeli: ikincisinde ucret alanlari ic ice tasindi
export const surumBir = () => ({
  id: "G7", agirlik: 3, postaKodu: "06800", notlar: "sozlesmeli musteri",
  ham: 8640, indirimler: [{ ad: "sozlesme", oran: 0.15 }, { ad: "hacim", oran: 0.1 }],
});

export const surumIki = () => ({
  id: "G7", agirlik: 3, postaKodu: "06800", notlar: "sozlesmeli musteri",
  ucret: { taban: 8640, indirimler: [{ ad: "sozlesme", oran: 0.15 }, { ad: "hacim", oran: 0.1 }] },
});
```

Üç istemci bu nesneyi doğrudan okur ve kendi biçimini üretir.

```js
// dtosuz/istemciler.mjs — uc istemci ic modelin alanlarini dogrudan okuyup bicimler
const TAVAN = 0.4;
const oran = (g) => Math.min(g.indirimler.reduce((t, i) => t + i.oran, 0), TAVAN);
const net = (g) => Math.round(g.ham * (1 - oran(g)));

export const liste = (g) => `${g.id}  ${g.agirlik} kg  ${net(g)}`;
export const fatura = (g) =>
  `${g.id}: taban ${g.ham}, ${g.indirimler.map((i) => `${i.ad} ${-Math.round(g.ham * i.oran)}`).join(", ")} = ${net(g)}`;
export const kutuk = (g) => `${g.id} net=${net(g)} indirim=${g.indirimler.length}`;
```

Üç istemcinin üçü de `ham` ve `indirimler` adlarını biliyor. İç modelin bu iki adı taşıdığı
varsayımı böylece üç ayrı yere yayılmış oldu.

## Çözüm: Sözleşmeyi Ayrı Kayıt Olarak Tanımlamak

Eşleyici, iç modelden dış sözleşmeyi üretir. İki iç sürüm için iki üretim işlevi vardır ama
ürettikleri kayıtlar aynıdır.

```js
// dto/esleyici.mjs — ic modelin her surumu icin ayni uc veri aktarim nesnesini uretir
const TAVAN = 0.4;

const kur = (id, agirlik, taban, indirimler) => {
  const oran = Math.min(indirimler.reduce((t, i) => t + i.oran, 0), TAVAN);
  const net = Math.round(taban * (1 - oran));
  return {
    liste: { kimlik: id, agirlik, net },
    fatura: { kimlik: id, taban, kalemler: indirimler.map((i) => ({ ad: i.ad, tutar: -Math.round(taban * i.oran) })), toplam: net },
    kutuk: { kimlik: id, net, indirimSayisi: indirimler.length },
  };
};

export const esleyiciBir = (g) => kur(g.id, g.agirlik, g.ham, g.indirimler);
export const esleyiciIki = (g) => kur(g.id, g.agirlik, g.ucret.taban, g.ucret.indirimler);
```

```js
// dto/istemciler.mjs — uc istemci yalniz veri aktarim nesnesinin alanlarini okur
export const liste = (d) => `${d.liste.kimlik}  ${d.liste.agirlik} kg  ${d.liste.net}`;
export const fatura = (d) =>
  `${d.fatura.kimlik}: taban ${d.fatura.taban}, ${d.fatura.kalemler.map((k) => `${k.ad} ${k.tutar}`).join(", ")} = ${d.fatura.toplam}`;
export const kutuk = (d) => `${d.kutuk.kimlik} net=${d.kutuk.net} indirim=${d.kutuk.indirimSayisi}`;
```

Sözleşme adlarının iç adlardan ayrıldığına dikkat etmek gerekir: içeride `id`, dışarıda
`kimlik`. Ayrım kasıtlıdır; iki adın aynı olması bir kolaylık gibi görünüp iki tarafı yeniden
birbirine bağlar.

## Değişim Yayılımının Sayılması

Ölçüm iç modeli birinci sürümden ikinci sürüme geçirir ve iki düzende ne olduğunu sayar. Bir
çıktı `undefined` ya da `NaN` içeriyorsa, ya da hata atıyorsa bozulmuş sayılır.

```js
// yayilim-say.mjs — ic model degistiginde bozulan istemci sayisi ve istemcideki ic alan adi
import { readFileSync } from "node:fs";
import { surumBir, surumIki } from "./alan.mjs";
import * as dogrudan from "./dtosuz/istemciler.mjs";
import { esleyiciBir, esleyiciIki } from "./dto/esleyici.mjs";
import * as dto from "./dto/istemciler.mjs";

const ADLAR = ["liste", "fatura", "kutuk"];
const dene = (f, girdi) => { try { return f(girdi); } catch { return "HATA"; } };
const saglam = (s) => /undefined|NaN|HATA/.test(s) === false;

function kosu(ad, birinci, ikinci) {
  const ilk = ADLAR.map((a) => dene(birinci[0][a], birinci[1]));
  const son = ADLAR.map((a) => dene(ikinci[0][a], ikinci[1]));
  const bozulan = son.filter((s) => saglam(s) === false).length;
  const degisen = son.filter((s, i) => s !== ilk[i]).length;
  console.log(`${ad}: bozulan istemci cikti = ${bozulan} / ${ADLAR.length}, degisen cikti = ${degisen} / ${ADLAR.length}`);
  return son;
}

console.log("ic model surum 1 -> surum 2");
kosu("dtosuz    ", [dogrudan, surumBir()], [dogrudan, surumIki()]);
const sonuc = kosu("dto ile   ", [dto, esleyiciBir(surumBir())], [dto, esleyiciIki(surumIki())]);
for (const s of sonuc) console.log(`  ${s}`);

const IC_ALAN = /\bg\.(ham|indirimler|notlar)\b|\bucret\.(taban|indirimler)\b/g;
for (const dosya of ["dtosuz/istemciler.mjs", "dto/istemciler.mjs", "dto/esleyici.mjs"]) {
  const m = readFileSync(dosya, "utf8");
  console.log(`${dosya.padEnd(24)} ic alan adi = ${[...m.matchAll(IC_ALAN)].length}`);
}

const dtoAlan = Object.values(esleyiciBir(surumBir())).reduce((t, d) => t + Object.keys(d).length, 0);
const satir = readFileSync("dto/esleyici.mjs", "utf8").split("\n").filter((s) => s.trim() !== "").length;
console.log(`dto alan sayisi = ${dtoAlan}, esleyici satir = ${satir}, alan basina satir = ${(satir / dtoAlan).toFixed(2)}`);
```

```sh
node yayilim-say.mjs
```

```
ic model surum 1 -> surum 2
dtosuz    : bozulan istemci cikti = 3 / 3, degisen cikti = 3 / 3
dto ile   : bozulan istemci cikti = 0 / 3, degisen cikti = 0 / 3
  G7  3 kg  6480
  G7: taban 8640, sozlesme -1296, hacim -864 = 6480
  G7 net=6480 indirim=2
dtosuz/istemciler.mjs    ic alan adi = 6
dto/istemciler.mjs       ic alan adi = 0
dto/esleyici.mjs         ic alan adi = 4
dto alan sayisi = 10, esleyici satir = 13, alan basina satir = 1.30
```

İç modelin biçimi değiştiğinde doğrudan okuyan üç istemcinin üçü de bozuldu. Eşleyici
arkasındaki üç istemcinin hiçbiri bozulmadı ve üç çıktının üçü birinci sürümdekiyle birebir
aynı kaldı — çıktı satırları bunu gösteriyor.

Sayının kaynağı sonraki üç satırda duruyor: istemci dosyası doğrudan okuyan düzende 6 iç alan
adı taşıyor, eşleyicili düzende 0. İç yapı hakkındaki bilgi 4 adla tek dosyada, eşleyicinin
içinde toplanmış durumda. Değişim yayılımı istemci sayısıyla büyüyen bir çarpımdan tek dosyalık
sabite indi.

## Bedelin Sayılması

Son satır bedeli veriyor. Üç sözleşme toplam 10 alan taşıyor ve eşleyici bunu 13 satırda
üretiyor: alan başına 1,3 satır. Bu satırların işlevsel bir karşılığı yoktur; iç adı dış ada
bağlamaktan başka iş yapmazlar. Yanına iki ek bedel gelir: 2 yeni dosya ve sınırdan her
geçişte 1 ek çağrı.

İkinci bedel bakım tarafındadır. Sözleşmeye bir alan eklenmesi iki yerde iş çıkarır: eşleyici
o alanı üretmeli, istemci onu okumalı. Alan üretilmezse istemci `undefined` görür ve ölçümdeki
bozulma sayacı bunu yakalar. Bu nedenle eşleyicinin ürettiği kayıt bir sınamayla
kilitlenmelidir; sözleşme sınaması olmadan eşleyici sessizce eksik kalabilir.

## Ne Zaman Uygulanmaz

Kalıbın kazancı iki sayının çarpımıdır: iç yapıya bağlı istemci sayısı ile iç yapının değişme
sıklığı. İkisinden biri düşükse kazanç bedelin altına iner.

Tek istemcili bir sınırda iç modelin değişmesi zaten o tek istemciyi ilgilendirir; eşleyici
onu 0 dosyadan korur ve karşılığında 13 satır ile 2 dosya ödetir. Aynı süreç içinde kalan ve
aynı takımın baktığı çağrılarda da durum budur: alan nesnesini doğrudan geçirmek 0 satır
tutar.

Ters yönde bir sınır daha var. Sözleşme iç modelin alan adlarını birebir kopyalıyorsa veri
aktarım nesnesi bir yalıtım kurmaz, yalnız bir kopyalama katmanı ekler. Ölçüde bu durum şöyle
görünür: iç model değiştiğinde eşleyici de değişir ve bozulma sayısı yine 3'e çıkar, çünkü
sözleşme iç yapının aynası olmuştur. Kalıbın işe yaraması için sözleşmenin iç modelden
**bağımsız** bir kararla tanımlanmış olması gerekir. Bu ayrımın adı Tasarım İlkeleri kursunda
konulmuştu: politika ile ayrıntının ayrılması.

## Özet

- Veri aktarım nesnesi dış sözleşmeyi ayrı bir düz kayıt olarak tanımlar; eşleyici iç
  modelden o kaydı üretir ve iç yapı bilgisini tek dosyada toplar.
- İç modelin biçimi değiştiğinde doğrudan okuyan 3 istemcinin 3'ü bozuldu; eşleyici
  arkasındaki 3 istemcinin 0'ı bozuldu ve üç çıktı birebir aynı kaldı.
- İstemci dosyası doğrudan okuyan düzende 6 iç alan adı taşıyordu, eşleyicili düzende 0;
  bilgi 4 adla eşleyicinin içine toplandı.
- Bedel sayıldı: 10 sözleşme alanı için 13 eşleyici satırı (alan başına 1,3 satır), 2 yeni
  dosya ve sınırdan her geçişte 1 ek çağrı.
- Kazanç istemci sayısı ile iç modelin değişme sıklığının çarpımıdır; tek istemcide ya da
  sözleşme iç adları birebir kopyaladığında kalıp bir kopyalama katmanına dönüşür.

## Sonraki Adım

Bu dersin istemcileri kitaplığa hangi kapıdan girdiklerini hiç sormadı; eşleyicinin ürettiği
kaydı hazır aldılar. Kaydı kimin ürettiği, senaryonun hangi sırayla yürüdüğü ve iş biriminin
nerede açılıp kapandığı hâlâ belirsiz. Dört istemci aynı senaryoyu kendi içinde tekrar
ederse adımlar dört kez yazılır. Sonraki ders uygulama sınırını servis katmanıyla tanımlar,
sunum tarafının bilmek zorunda olduğu tip sayısını ve erişim zinciri derinliğini ölçer, ikinci
bir istemci eklendiğinde tekrar eden senaryo adımı sayısını sayar.
