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
endBu ö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.
Görev
KolayKapanış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ınselfü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 birnamealanı 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
namealanı (Keeperyazdırmalıdır) keeper.secretadresine erişmeye çalıştığınızda ne olduğu (nilolmalıdır)keeper._secretadresine erişmeye çalıştığınızda ne olduğu (bu danilolmalıdır)
- Keeper'ın
Bir girdi alacaksınız:
- 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: nilHangi 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: nilKopya 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
endBu ö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>")
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
1'Self' Kavramı
Fonksiyonlu TablolarAçık 'self'İki Nokta SözdizimiNokta vs İki NoktaÖzet - Hareket Eden Nokta4Proje: Dijital Banka
Proje KurulumuPara Yatırma Metodu7Çok Biçimlilik ve Geçersiz Kılma
Metotları Geçersiz KılmaÜst Sınıf Metotlarını ÇağırmaDuck TypingOrtak ArayüzTür KontrolüÖzet - Çalışan Rolleri2Sınıf Prototip Kalıbı
Prototip Kavramı__index ile Bağlama:new() KurucusuÖznitelikleri BaşlatmaBağımsız ÖrneklerÖzet - Araba Fabrikası5OOP'de Operatör Aşırı Yükleme
Nesneleri ToplamaNesneleri ÇıkarmaNesneleri BirleştirmeNesneleri Karşılaştırma (<, >)Özet - Cüzdan Matematiği8Kapsülleme
Adlandırma KurallarıGizlilik için Closure'larClosure'lar Aracılığıyla ErişimSalt Okunur TablolarDoğrulama MantığıÖzet - Güvenli Kasa11Tasarım Kalıpları (Lite)
Fabrika FonksiyonlarıSingleton TablosuIterator KalıbıObserver (Dinleyici)Özet - Logger Fabrikası3Nesne Durumu ve Davranışı
Örnek DeğişkenleriGetter MetotlarıSetter MetotlarıHesaplanmış ÖzelliklerString BiçimlendirmeEşitlik KontrolleriÖzet - Öğrenci Notu6Kalıtımın Temelleri
Kalıtım KurulumuMetot KalıtımıConstructor'ı GenişletmeAlt Sınıf Metotları EklemePaylaşılan ve BenzersizÖzet - Şekil Hiyerarşisi