Menu
Coddy logo textTech

Gizlilik için Closure'lar

Coddy'nin Lua Journey'sinin Object Oriented Programming bölümünün bir parçası — ders 44 / 70.

İsimlendirme kuralları niyeti belirtir, ancak aslında erişimi engellemez. Herkes hala player._health = 999 yazabilir ve bu çalışır. Gerçek gizlilik için Lua farklı bir yaklaşım sunar: verileri self üzerinde değil, yapıcı (constructor) içindeki yerel değişkenlerde saklamak.

Temel içgörü, bir fonksiyonun içindeki yerel değişkenlerin yalnızca o fonksiyonun içinden ve onun içinde tanımlanan fonksiyonlardan erişilebilir olmasıdır. Buna bir closure denir:

local Counter = {}
Counter.__index = Counter

function Counter:new()
    local count = 0  -- Gerçekten gizli! self üzerinde değil.
    
    local obj = {}
    setmetatable(obj, Counter)
    return obj
end

Bu örnekte, count yalnızca :new() fonksiyonunun içinde bulunur. obj içinde saklanmaz, bu yüzden ona dışarıdan erişmenin bir yolu yoktur—myCounter.count nil değerini döndürür ve atlanacak alt çizgi ön ekli bir alan yoktur.

count değişkeni closure kapsamı içinde yer alır. Nesne var olduğu sürece kalıcılığını korur, ancak dış koddan tamamen gizlenmiştir. Sadece nazik bir öneri olan self._count aksine, bu yaklaşım veriyi gerçekten erişilemez kılar.

Elbette, gizli verilerle hiçbir zaman etkileşime giremiyorsanız bu veriler kullanışlı değildir. Bir sonraki derste, gerçek kapsüllemeyi (encapsulation) korurken size kontrollü erişim sağlayan, bu private değişkenleri okuyabilen ve değiştirebilen metotları constructor içinde nasıl tanımlayacağınızı öğreneceksiniz.

challenge icon

Görev

Kolay

Kapanışları (closures) kullanarak gerçek veri gizliliğini gösteren bir SecretKeeper sınıfı oluşturalım! Önceki dersteki alt çizgi kuralının aksine, bu yaklaşım verileri nesne dışından gerçekten erişilemez hale getirir.

Kodunuzu iki dosya halinde düzenleyeceksiniz:

  • SecretKeeper.lua: Sırrın self üzerinde değil, yapıcı (constructor) içindeki yerel bir değişkende saklandığı bir sınıf oluşturun. :new(secretValue) yapıcısı, sırrı yalnızca kapanış içinde var olan yerel bir değişkende saklamalıdır. Şimdilik, nesnenin bu sırra erişmek için herhangi bir yolu olmayacak (bu bir sonraki derste gelecek!), ancak nesnenin çalıştığını doğrulayabilmemiz için örnek üzerinde "Keeper" olarak ayarlanmış genel bir name alanı da saklamalısınız.
  • main.lua: SecretKeeper modülünüzü dahil edin ve girdiden bir sır değeri okuyun. Bu sırla bir SecretKeeper örneği oluşturun. Ardından üç şeyi yazdırarak sırrın gerçekten gizli olduğunu kanıtlayın:
    • Keeper'ın name alanı (Keeper yazdırmalıdır)
    • keeper.secret adresine erişmeye çalıştığınızda ne olduğu (nil olmalıdır)
    • keeper._secret adresine erişmeye çalıştığınızda ne olduğu (bu da nil olmalıdır)

Bir girdi alacaksınız:

  1. Saklanacak sır değeri (örneğin, TopSecret123)

Çıktınız, genel alan çalışırken sırrın tamamen gizlendiğini gösteren üç satır olmalıdır:

Name: Keeper
secret: nil
_secret: nil

Hangi sırrı girerseniz girin çıktı aynı olacaktır; çünkü ona erişmenin hiçbir yolu yoktur! Yapıcı içindeki yerel değişken dış dünyaya görünmezdir. Bu, kapanış tabanlı gizliliğin alt çizgi adlandırma kuralından temelden farklı olduğunu kanıtlar.

Örneğin, girdi MyPassword ise, çıktı yine şu şekilde olmalıdır:

Name: Keeper
secret: nil
_secret: nil

Kopya kağıdı

Lua'da gerçekten özel (private) veriler oluşturmak için, bunları self üzerinde değil, yapıcı (constructor) içindeki yerel değişkenlerde saklayın. Bu bir closure kullanır; yerel değişkenlere yalnızca tanımlandıkları fonksiyon ve onun içinde tanımlanan diğer fonksiyonlar içinden erişilebilir.

Özel veriye sahip bir sınıf örneği:

local Counter = {}
Counter.__index = Counter

function Counter:new()
    local count = 0  -- Gerçekten özel! self üzerinde değil.
    
    local obj = {}
    setmetatable(obj, Counter)
    return obj
end

Bu örnekte, count yalnızca :new() fonksiyonunun içinde mevcuttur. obj içinde saklanmaz, bu nedenle myCounter.count değeri nil döner. Dışarıdan erişmenin hiçbir yolu yoktur; self._count (ki bu sadece bir isimlendirme kuralıdır) aksine, bu yaklaşım veriyi gerçekten erişilemez kılar.

Değişken, nesne var olduğu sürece kalıcıdır ancak dış koddan tamamen gizli kalır ve gerçek bir kapsülleme (encapsulation) sağlar.

Kendin dene

-- SecretKeeper modülünü dahil et
local SecretKeeper = require('SecretKeeper')

-- Girdiden gizli değeri oku
local secretValue = io.read()

-- YAPILACAK: Gizli değer ile bir SecretKeeper örneği oluştur

-- YAPILACAK: Keeper'ın name alanını yazdır (format: "Name: <name>")

-- YAPILACAK: keeper.secret erişildiğinde ne olduğunu yazdır (format: "secret: <value>")

-- YAPILACAK: keeper._secret erişildiğinde ne olduğunu yazdır (format: "_secret: <value>")
quiz iconKendini test et

Bu ders kısa bir quiz içerir. Soruları yanıtlamak ve ilerlemeni kaydetmek için derse başla.

Object Oriented Programming bölümündeki tüm dersler