İçeriğe geç
academia.sh

Ders 16 / 30

Komut

Gönderi üzerindeki işlemlerin doğrudan çağrı olarak yazılması ile nesneye çevrilmesinin karşılaştırılması: geri alınabilen işlem sayısı, denetim izi kaydı sayısı, izi doğrudan sürümde üretmek için düzenlenen işlem gövdesi sayısı ve ortaya çıkan ortak bağlaşım, kalıbın bedeli olarak dosya sayısı ile çağrı derinliği.

İçindekiler

Gözlemci olmuş bir şeyi haber veriyordu: bildirim gönderildiği anda durum çoktan değişmişti ve geri dönüş yoktu. Kitaplığın operatör tarafında tersi isteniyor. Bir gönderiye indirim uygulanması, rotasının değiştirilmesi ve iptali operatör kararıyla yapılıyor; yanlış uygulanan bir işlemin geri alınması gerekiyor. Bugün bu üç işlem doğrudan alan değiştiren çağrılardır ve çağrı bittiğinde eski değer kaybolmuştur.

Komut (command) kalıbı, bir işlemi çağrı olmaktan çıkarıp nesne yapar: ne yapılacağı ve hangi parametreyle yapılacağı bir nesnenin içinde durur, çağrılmadan önce elde tutulabilir, sıraya konabilir, kaydedilebilir ve tersi aynı nesneden istenebilir. Ölçülecek sayılar geri alınabilen işlem sayısı, denetim izi kaydı sayısı ve kesişen bir iş eklendiğinde düzenlenen işlem gövdesi sayısıdır. Bedel tarafında dosya sayısı ve çağrı derinliği durur.

Alan Nesnesi ve İki Düzen

Alan nesnesi iki sürümde ortaktır. Her yazma işleminde kendi dosyalarımıza ait çağrı çerçevesi sayısını kaydeder; bu sayı dolaylılık basamağının koşumdaki karşılığıdır.

mkdir -p dogrudan komut
// gonderi.mjs — alan nesnesi; her yazma isleminde cagri derinligini kaydeder
export const gonderi = (kod) => {
  const durum = { kod, indirim: 0, rota: "R1", iptal: "hayir" };
  const derinlikler = [];
  return {
    durum,
    derinlikler,
    yaz(alan, deger) {
      durum[alan] = deger;
      derinlikler.push(new Error().stack.split("\n").filter((s) => s.includes(".mjs:")).length);
    },
    ozet: () => `${durum.kod} indirim=${durum.indirim} rota=${durum.rota} iptal=${durum.iptal}`,
  };
};

Birinci düzen üç işlemi üç işlev olarak yazar. Bir işlemin tersi hiçbir yerde tanımlı değildir; indirimUygula çağrıldıktan sonra eski oranı bilen kimse kalmaz.

// dogrudan/islem.mjs — islemler alani dogrudan yazar, tersi yoktur
export const indirimUygula = (g, oran) => g.yaz("indirim", oran);
export const rotaDegistir = (g, rota) => g.yaz("rota", rota);
export const iptalEt = (g) => g.yaz("iptal", "evet");

İkinci düzende her işlem bir nesne üretir. Nesne, uygulanmadan önceki değeri kendi kapanışında saklar ve geriAl yöntemiyle onu geri yazar.

// komut/indirim.mjs
export const indirimKomutu = (oran) => {
  let onceki;
  return {
    ad: `indirim(${oran})`,
    uygula(g) {
      onceki = g.durum.indirim;
      g.yaz("indirim", oran);
    },
    geriAl(g) {
      g.yaz("indirim", onceki);
    },
  };
};
// komut/rota.mjs
export const rotaKomutu = (rota) => {
  let onceki;
  return {
    ad: `rota(${rota})`,
    uygula(g) {
      onceki = g.durum.rota;
      g.yaz("rota", rota);
    },
    geriAl(g) {
      g.yaz("rota", onceki);
    },
  };
};
// komut/iptal.mjs
export const iptalKomutu = () => {
  let onceki;
  return {
    ad: "iptal",
    uygula(g) {
      onceki = g.durum.iptal;
      g.yaz("iptal", "evet");
    },
    geriAl(g) {
      g.yaz("iptal", onceki);
    },
  };
};

Üç nesnenin ortak sözleşmesi ad, uygula ve geriAl üçlüsüdür. Bu sözleşme, komutu çalıştıran nesnenin komutun ne yaptığını bilmeden onu yönetmesine yeter. Çalıştırıcı geçmiş yığıtını tutar ve her çağrıyı denetim izine yazar.

// komut/calistirici.mjs — istemleri calistirir, gecmis yigitini ve denetim izini tutar
export const calistirici = () => {
  const gecmis = [];
  const iz = [];
  return {
    iz,
    calistir(komut, g) {
      komut.uygula(g);
      gecmis.push([komut, g]);
      iz.push(`uygula  ${komut.ad}`);
    },
    geriAl(adet) {
      let sayi = 0;
      while (sayi < adet && gecmis.length > 0) {
        const [komut, g] = gecmis.pop();
        komut.geriAl(g);
        iz.push(`geri-al ${komut.ad}`);
        sayi += 1;
      }
      return sayi;
    },
  };
};

Beş İşlem, Üç Geri Alma

Sürücü betik aynı beş işlemi iki sürüme de uygular, sonra üçünü geri almayı dener ve son durumları karşılaştırır.

// kosum.mjs — bes islem uygulanir, ucu geri alinir; iki surum karsilastirilir
import { gonderi } from "./gonderi.mjs";
import { indirimUygula, rotaDegistir, iptalEt } from "./dogrudan/islem.mjs";
import { indirimKomutu } from "./komut/indirim.mjs";
import { rotaKomutu } from "./komut/rota.mjs";
import { iptalKomutu } from "./komut/iptal.mjs";
import { calistirici } from "./komut/calistirici.mjs";

const a = gonderi("GN-7");
indirimUygula(a, 10);
rotaDegistir(a, "R2");
indirimUygula(a, 15);
rotaDegistir(a, "R3");
iptalEt(a);
console.log(`dogrudan  bes islem sonrasi : ${a.ozet()}`);
console.log(`dogrudan  geri alinan islem : 0`);

const b = gonderi("GN-7");
const k = calistirici();
for (const komut of [indirimKomutu(10), rotaKomutu("R2"), indirimKomutu(15), rotaKomutu("R3"), iptalKomutu()]) {
  k.calistir(komut, b);
}
console.log(`komut     bes islem sonrasi : ${b.ozet()}`);
const geri = k.geriAl(3);
console.log(`komut     geri alinan islem : ${geri}`);
console.log(`komut     geri alma sonrasi : ${b.ozet()}`);
console.log(`cagri derinligi (dogrudan/komut): ${a.derinlikler[0]} / ${b.derinlikler[0]}`);
console.log(`denetim izi kaydi (dogrudan/komut): 0 / ${k.iz.length}`);
dogrudan  bes islem sonrasi : GN-7 indirim=15 rota=R3 iptal=evet
dogrudan  geri alinan islem : 0
komut     bes islem sonrasi : GN-7 indirim=15 rota=R3 iptal=evet
komut     geri alinan islem : 3
komut     geri alma sonrasi : GN-7 indirim=10 rota=R2 iptal=hayir
cagri derinligi (dogrudan/komut): 3 / 4
denetim izi kaydi (dogrudan/komut): 0 / 8

İki satır ölçümün geçerlilik koşulunu veriyor: beş işlem sonrası iki sürümün özeti birebir aynı. Sonrası kazançtır. Geri alınan işlem sayısı 0’a karşı 3; geri alma sonrası durum, ilk iki işlemin uygulandığı duruma birebir dönmüş. Denetim izi 0’a karşı 8 kayıt taşıyor — beş uygulama ve üç geri alma. Bu sekiz kayıt için hiçbir işlem gövdesine dokunulmadı; kayıt, komutun ad alanını okuyan çalıştırıcıda üretildi.

Çağrı derinliği bedeli veriyor: 3’e karşı 4. Bu sayılar kendi dosyalarımıza ait çağrı çerçevelerini sayar; taban değer koşum betiğinin çerçevesini de içerdiği için mutlak sayı önemli değil, iki sürüm arasındaki bir basamak farkı önemlidir. Operatör isteminden alan yazmasına giden yol bir çağrı uzadı.

Denetim İzini Doğrudan Sürüme Eklemek

Sekiz kayıtlık izi doğrudan sürümde de üretmek istenirse üç işlem gövdesinin de düzenlenmesi gerekir; kaydın tutulacağı yer de bir modül düzeyi dizi olmak zorundadır, çünkü üç işlevin paylaşacağı başka bir yer yoktur.

// denetim.mjs — denetim izini iki surume de ekler ve degisimi olcer
import { cpSync, readFileSync, writeFileSync } from "node:fs";

cpSync("dogrudan", "dogrudan-yeni", { recursive: true });
writeFileSync(
  "dogrudan-yeni/islem.mjs",
  `// dogrudan/islem.mjs — islemler alani dogrudan yazar, tersi yoktur
export const iz = [];
export const indirimUygula = (g, oran) => {
  iz.push(\`uygula  indirim(\${oran})\`);
  g.yaz("indirim", oran);
};
export const rotaDegistir = (g, rota) => {
  iz.push(\`uygula  rota(\${rota})\`);
  g.yaz("rota", rota);
};
export const iptalEt = (g) => {
  iz.push("uygula  iptal");
  g.yaz("iptal", "evet");
};
`,
);
console.log(`duzenlenen islem govdesi = ${(readFileSync("dogrudan-yeni/islem.mjs", "utf8").match(/iz\.push/g) ?? []).length}`);
console.log(`yeni modul duzeyi paylasilan durum = ${(readFileSync("dogrudan-yeni/islem.mjs", "utf8").match(/^export const iz = \[\];$/m) ?? []).length}`);
console.log(`komut surumunde duzenlenen islem govdesi = 0`);
duzenlenen islem govdesi = 3
yeni modul duzeyi paylasilan durum = 1
komut surumunde duzenlenen islem govdesi = 0

Üç gövdeye karşı sıfır gövde. Sayının yanında bir de tür farkı var: doğrudan sürüme eklenen iz dizisi modül düzeyinde paylaşılan değiştirilebilir durumdur, yani tasarım ilkeleri kursunda en güçlü biçim olarak ölçülen ortak bağlaşım. Üç işlev bu diziyi birlikte değiştirir; ikinci bir iz gerektiğinde ya da testte izin sıfırlanması gerektiğinde üçü birlikte etkilenir. Komut sürümünde iz çalıştırıcı örneğine aittir, her koşum kendi izini taşır ve paylaşılan modül durumu sayısı sıfır kalır.

Bedelin Sayımı

echo "dosya sayisi: dogrudan=$(ls dogrudan | wc -l | tr -d ' ')  komut=$(ls komut | wc -l | tr -d ' ')"
echo "tersini bilen dosya: dogrudan=0  komut=$(grep -l '^    geriAl(g) {$' komut/*.mjs | wc -l | tr -d ' ')"
echo "gecmis yigitini tutan dosya: komut=$(grep -l 'gecmis.push' komut/*.mjs | wc -l | tr -d ' ')"
dosya sayisi: dogrudan=1  komut=4
tersini bilen dosya: dogrudan=0  komut=3
gecmis yigitini tutan dosya: komut=1

Bir dosyaya karşı dört dosya. Kalıbın bedeli işlem başına bir dosya ve bir tiptir; kazancı ise işlem sayısından bağımsızdır, çünkü geçmiş yığıtını tutan yer tektir. Dördüncü bir işlem eklendiğinde bedel bir dosya artar, geri alma ve denetim izi ise kendiliğinden çalışır. Üç satır bir de sınırı gösteriyor: tersini bilen dosya sayısı işlem sayısına eşit olmak zorundadır, yani tersi tanımlanamayan bir işlem varsa kalıp geri alma kazancını vermez.

Özet

  • Komut kalıbı bir işlemi nesneye çevirir; nesne ne yapılacağını, parametresini ve tersini taşır, bu yüzden uygulanmadan önce tutulabilir ve sonradan geri alınabilir.
  • Aynı beş işlem iki sürümde birebir aynı durumu üretti; geri alınan işlem sayısı 0’a karşı 3 çıktı ve geri alma sonrası durum ilk iki işlemin durumuna birebir döndü.
  • Denetim izi komut sürümünde 8 kayıt üretti ve bunun için hiçbir işlem gövdesi düzenlenmedi; aynı izi doğrudan sürümde üretmek 3 gövdenin düzenlenmesini ve 1 modül düzeyi paylaşılan durumu, yani ortak bağlaşımı gerektirdi.
  • Bedel: dosya sayısı 1’den 4’e çıktı, çağrı derinliği 3’ten 4’e yükseldi; tersini bilen dosya sayısı işlem sayısına eşit olmak zorundadır.
  • Kalıbın kazancı işlem sayısından bağımsızdır, bedeli işlem sayısıyla doğrusal büyür.

Sonraki Adım

Üç komut aynı üç adımı aynı sırayla yapıyor: önceki değeri sakla, yeni değeri yaz, kaydı tut. Sıra her komutta aynı, yalnız ortadaki adım değişiyor. Aynı tekrar kitaplığın ücret hesaplama tarafında daha büyük ölçekte var: yurt içi, yurt dışı ve ekspres taşıyıcı için ücretlendirme altı adımdan geçiyor ve üç dosya bu altı adımı ayrı ayrı sıralıyor. Sıraya bir adım eklendiğinde üç dosya da düzenleniyor. Sonraki ders yinelenen satır sayısını ve adım sırası değiştiğinde düzenlenen dosya sayısını ölçer, sonra iskeleti tek yere alıp aynı sayıları yeniden hesaplar.

İ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