Menu
Coddy logo textTech

Singleton Tablosu

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

Bazen tüm programınızda bir şeyin tam olarak bir örneğine ihtiyaç duyarsınız; bir yapılandırma yöneticisi, bir günlükleme sistemi veya oyun ayarları. Birden fazla kopya oluşturmak sorunlara yol açar: hangisi doğru veriye sahip? Singleton deseni yalnızca bir örneğin var olmasını sağlar.

Lua'da, modüllerin çalışma şekli sayesinde bir Singleton uygulamak şaşırtıcı derecede basittir. Bir modülü require ettiğinizde, Lua sonucu önbelleğe alır. require fonksiyonuna yapılan sonraki çağrılar, yeni bir tablo değil, önbelleğe alınmış tabloyu döndürür.

-- GameConfig.lua
local GameConfig = {
    volume = 80,
    difficulty = "normal"
}

function GameConfig:setVolume(v)
    self.volume = v
end

return GameConfig

Şimdi, programınızın herhangi bir yerinde:

local config1 = require("GameConfig")
local config2 = require("GameConfig")

config1:setVolume(50)
print(config2.volume)  -- 50 (aynı tablo!)

Hem config1 hem de config2 tam olarak aynı tabloya başvurur. Bir değişken üzerinden yapılan değişiklikler diğeri üzerinden görülebilir. Bu otomatik olarak gerçekleşir çünkü Lua'nın require fonksiyonu döndürülen değeri package.loaded içinde saklar ve onu tekrar kullanır.

Yeni nesneler oluşturan Factory pattern'in aksine, bir Singleton tüm uygulamanız genelinde paylaşılan bir durumu garanti eder. Bu, kodunuzun birden fazla bölümünün tutarlı bir şekilde erişmesi ve değiştirmesi gereken global ayarlar için idealdir.

challenge icon

Görev

Kolay

Singleton desenini kullanarak bir oyun ayarları yöneticisi oluşturalım! Programınızın her parçasının, kaç kez çağrılırsa çağrılsın, tam olarak aynı ayarlara erişmesini sağlayan bir yapılandırma modülü oluşturacaksınız.

Kodunuzu iki dosya halinde düzenleyeceksiniz:

  • GameSettings.lua: Oyun yapılandırmasını saklayan bir Singleton modülü oluşturun. Ayarlar tablonuz musicVolume (70 ile başlar), sfxVolume (100 ile başlar) ve difficulty ("normal" ile başlar) içermelidir. Bu ayarları değiştirmek için üç yöntem ekleyin: :setMusicVolume(value), :setSfxVolume(value) ve :setDifficulty(level). Modülün sonunda tabloyu döndürmeyi unutmayın!
  • main.lua: GameSettings modülünüzü iki farklı değişkene çağırarak (require) Singleton'ın çalıştığını kanıtlayın. Müzik sesini ve zorluğu değiştirmek için ilk değişkeni kullanın. Ardından, üç ayarın tümünü yazdırmak için ikinci değişkeni kullanın; eğer Singleton doğru çalışıyorsa, her iki değişken de aynı tabloya başvurur, bu nedenle biri aracılığıyla yapılan değişiklikler diğeri aracılığıyla görünür olur.

İki girdi alacaksınız:

  1. Yeni müzik sesi (bir sayı)
  2. Yeni zorluk seviyesi ("easy" veya "hard" gibi bir dize)

Ayarları ilk değişken üzerinden değiştirdikten sonra, ikinci değişkeni kullanarak üç ayarı şu sırayla her biri kendi satırında olacak şekilde yazdırın: müzik sesi, sfx sesi ve ardından zorluk.

Örneğin, girdiler 50 ve hard ise, çıktı şöyle olmalıdır:

50
100
hard

Girdiler 25 ve easy ise, çıktı şöyle olmalıdır:

25
100
easy

Sfx sesinin hiç değiştirmediğimiz için varsayılan değeri olan 100'de kaldığına, ancak müzik sesinin ve zorluğun ilk değişken üzerinden yapılan değişiklikleri yansıttığına dikkat edin; bu, her iki değişkenin de aynı Singleton örneğine işaret ettiğini kanıtlar!

Kopya kağıdı

Singleton deseni, tüm programınız boyunca bir nesnenin yalnızca bir örneğinin bulunmasını sağlar. Bu, birden fazla örneğin veri tutarsızlığına neden olacağı yapılandırma yöneticileri, günlükleme sistemleri veya oyun ayarları için kullanışlıdır.

Lua'da Singleton deseni, modül sistemi aracılığıyla doğal bir şekilde uygulanır. Bir modülü require ettiğinizde, Lua sonucu package.loaded içinde önbelleğe alır. Sonraki require çağrıları, yeni bir tablo değil, aynı önbelleğe alınmış tabloyu döndürür.

Bir Singleton modülü oluşturma:

-- GameConfig.lua
local GameConfig = {
    volume = 80,
    difficulty = "normal"
}

function GameConfig:setVolume(v)
    self.volume = v
end

return GameConfig

Singleton'ı kullanma:

local config1 = require("GameConfig")
local config2 = require("GameConfig")

config1:setVolume(50)
print(config2.volume)  -- 50 (aynı tablo!)

Hem config1 ve config2 tam olarak aynı tabloya başvurur. Bir değişken üzerinden yapılan değişiklikler diğeri üzerinden anında görünür ve tüm uygulamanızda paylaşılan bir durum (state) sağlar.

Singleton deseni Factory deseninden farklıdır: Factory yeni nesneler oluştururken, Singleton tutarlı bir duruma sahip tek bir paylaşılan örnek garanti eder.

Kendin dene

-- main.lua - Singleton desenini göster

-- Girdileri oku
local newMusicVolume = tonumber(io.read())
local newDifficulty = io.read()

-- YAPILACAK: GameSettings modülünü bir değişkene aktar (örneğin, settings1)

-- YAPILACAK: GameSettings modülünü TEKRAR FARKLI bir değişkene aktar (örneğin, settings2)
-- (Eğer Singleton doğru çalışıyorsa, her iki değişken de aynı tabloyu referans alır!)

-- YAPILACAK: İLK değişkeni kullanarak:
--   - Müzik sesini newMusicVolume olarak ayarla
--   - Zorluğu newDifficulty olarak ayarla

-- YAPILACAK: Ayarları yazdırmak için İKİNCİ değişkeni kullan
-- Her birini kendi satırında yazdır: musicVolume, sfxVolume, difficulty
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