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.