Singleton Kalıbı
Coddy'nin C Journey'sinin Object Oriented Programming bölümünün bir parçası — ders 54 / 61.
Bazen tüm programınız boyunca bir nesnenin tam olarak bir örneğine ihtiyaç duyarsınız — bir yapılandırma yöneticisi, bir günlükleme sistemi veya bir veritabanı bağlantısı. Singleton deseni, yalnızca bir örneğin var olmasını sağlar ve ona küresel bir erişim noktası sunar.
C'de bunu, bir kaynak dosyası içindeki static bir değişkeni kullanarak uygularız. Dosya kapsamındaki static ifadesinin, değişkenin o dosyaya özel olduğu ve programın ömrü boyunca kalıcı olduğu anlamına geldiğini unutmayın. Bir getter fonksiyonu ile birleştirildiğinde bu, Singleton yapımızı oluşturur:
// config.c
#include "config.h"
#include <stdlib.h>
struct Config {
int max_connections;
int timeout;
};
static Config* instance = NULL;
Config* get_config(void) {
if (instance == NULL) {
instance = malloc(sizeof(Config));
instance->max_connections = 100;
instance->timeout = 30;
}
return instance;
}Sihir get_config() içinde gerçekleşir. İlk çağrı örneği oluşturur ve başlatır. Sonraki her çağrı aynı işaretçiyi döndürür.
static anahtar kelimesi, instance değişkeninin fonksiyon çağrıları arasında değerini korumasını ve diğer dosyalardan gizli kalmasını sağlar.
Header'dan, kullanıcılar yalnızca getter fonksiyonunu görürler; statik değişkene doğrudan erişemezler veya onu değiştiremezler. get_config() fonksiyonunu kaç kez veya nereden çağırırsanız çağırın, her zaman aynı nesneyi alırsınız.
Görev
KolaySingleton desenini kullanarak uygulama genelindeki yapılandırmayı yöneten bir Settings modülü oluşturalım. Kodunuz ayarları kaç kez isterse istesin, her zaman tam olarak aynı örneği (instance) almalıdır.
Kodunuzu üç dosya halinde düzenleyeceksiniz:
settings.h: Bir ileri bildirim (forward declaration) kullanarak opak birSettingstürü bildirin (struct gövdesi gizli kalır). Singleton örneğine bir işaretçi döndüren birget_settingsfonksiyonu ile iki yapılandırma değeri için getter ve setter fonksiyonlarını bildirin:volume(bir tam sayı) vebrightness(bir tam sayı). Burada include guard kullanımı zorunludur.settings.c: Sihrin gerçekleştiği yer burasıdır.volumevebrightnessalanlarına sahip gerçekSettingsstruct yapısını tanımlayın. Tek örneği tutmak içinstaticbir işaretçi değişkeni oluşturun (başlangıçtaNULLolarak atanmış).get_settingsfonksiyonunu, ilk çağrıda örneği tahsis edip varsayılan değerlerle (volume: 50, brightness: 75) başlatacak, sonraki çağrılarda ise sadece mevcut örneği döndürecek şekilde uygulayın. Gizli alanlara erişmek ve bunları değiştirmek için getter ve setter fonksiyonlarını uygulayın.main.c: Singleton'ın doğru çalıştığını gösterin. Yeni ses ve parlaklık değerlerini temsil eden iki tam sayı okuyun.get_settingsfonksiyonunu iki kez çağırın ve sonuçları iki farklı işaretçi değişkeninde saklayın. Giriş değerleriyle ses ve parlaklığı güncellemek için ilk işaretçiyi kullanın. Ardından, her iki değeri de almak ve yazdırmak için ikinci işaretçiyi kullanın. Eğer Singleton çalışıyorsa, bir işaretçi üzerinden yapılan değişiklikler diğeri üzerinden görülebilir olacaktır.
Programınız iki giriş alacaktır:
- Yeni ses (volume) değeri
- Yeni parlaklık (brightness) değeri
Değerleri bir işaretçi üzerinden değiştirip diğeri üzerinden okuduktan sonra, ses ve parlaklığı ayrı satırlara yazdırın.
Girişler 80 ve 100 olduğunda örnek çıktı:
80
100Girişler 25 ve 60 olduğunda örnek çıktı:
25
60Girişler 0 ve 50 olduğunda örnek çıktı:
0
50Buradaki temel nokta, her iki işaretçinin de bellekteki aynı nesneyi göstermesidir — Singleton deseninin özü budur. Kaynak dosyanızın içindeki statik değişken, yalnızca bir örneğin var olmasını sağlar ve bu örnek programın tüm ömrü boyunca kalıcı olur.
Kopya kağıdı
Singleton deseni, bir nesnenin tüm program boyunca yalnızca bir örneğinin bulunmasını sağlar ve bu nesneye global bir erişim noktası sunar.
C dilinde, bir kaynak dosyası içinde static bir değişken ve bir alıcı (getter) fonksiyonu kullanarak bir Singleton uygulayın:
// config.c
#include "config.h"
#include <stdlib.h>
struct Config {
int max_connections;
int timeout;
};
static Config* instance = NULL;
Config* get_config(void) {
if (instance == NULL) {
instance = malloc(sizeof(Config));
instance->max_connections = 100;
instance->timeout = 30;
}
return instance;
}Önemli noktalar:
- Dosya kapsamındaki
staticanahtar kelimesi, değişkeni o dosyaya özel kılar ve programın ömrü boyunca kalıcı olmasını sağlar - Alıcı (getter) fonksiyonu, ilk çağrıda örneğin
NULLolup olmadığını kontrol eder, onu oluşturur ve başlatır, ardından geri döndürür - Sonraki çağrılar aynı işaretçiyi (pointer) döndürür
- Kullanıcılar alıcı fonksiyonu yalnızca başlık dosyası (header) aracılığıyla görür; statik değişkene doğrudan erişemezler veya onu değiştiremezler
- Alıcı fonksiyonu kaç kez veya nereden çağırırsanız çağırın, her zaman aynı nesneyi alırsınız
Kendin dene
#include <stdio.h>
#include "settings.h"
int main() {
int new_volume, new_brightness;
scanf("%d", &new_volume);
scanf("%d", &new_brightness);
// TODO: get_settings fonksiyonunu iki kez çağırın ve iki farklı işaretçi (pointer) değişkeninde saklayın
// TODO: Giriş değerleriyle volume ve brightness değerlerini güncellemek için ilk işaretçiyi kullanın
// TODO: volume ve brightness değerlerini almak ve yazdırmak için ikinci işaretçiyi kullanın
// (Bu, her iki işaretçinin de aynı singleton örneğini gösterdiğini kanıtlar)
return 0;
}
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
1Modüler Programlama Temelleri
Başlık DosyalarıInclude Guard'larKaynak DosyalarıStatik FonksiyonlarÖzet: Modüler Hesap Makinesi4Kapsülleme
Opaque Pointer KavramıOpaque Struct TanımlamaGetter ve Setter MetotlarıSetter Metotlarında DoğrulamaÖzet: Gizli Kutu2Nesneler ve Metotlar
Nesne Olarak Struct'lar'Self' İşaretçisiConst Doğruluğuİşaretçi vs DeğerYardımcı MetotlarÖzet: Point Manager5Proje: Basit Banka Hesabı
Proje KurulumuHesabın Oluşturulması3Nesne Yaşam Döngüsü
Constructor DeseniDestructor DeseniStack İlklendirmeDerin KopyalamaÖzet: String Wrapper6Kompozisyon Yoluyla Kalıtım
Struct Gömmeİlk Üye KuralıÜst Üyelere ErişimUpcastingÖzet: Şekil Hiyerarşisi