Menu
Coddy logo textTech

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.

challenge icon

Görev

Kolay

Singleton 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 bir Settings türü bildirin (struct gövdesi gizli kalır). Singleton örneğine bir işaretçi döndüren bir get_settings fonksiyonu ile iki yapılandırma değeri için getter ve setter fonksiyonlarını bildirin: volume (bir tam sayı) ve brightness (bir tam sayı). Burada include guard kullanımı zorunludur.
  • settings.c: Sihrin gerçekleştiği yer burasıdır. volume ve brightness alanlarına sahip gerçek Settings struct yapısını tanımlayın. Tek örneği tutmak için static bir işaretçi değişkeni oluşturun (başlangıçta NULL olarak atanmış). get_settings fonksiyonunu, 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_settings fonksiyonunu 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:

  1. Yeni ses (volume) değeri
  2. 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
100

Girişler 25 ve 60 olduğunda örnek çıktı:

25
60

Girişler 0 ve 50 olduğunda örnek çıktı:

0
50

Buradaki 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 static anahtar 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 NULL olup 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;
}
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