Singleton Design Pattern (Tasarım Kalıbı) Nedir? Ne Tür Durumlarda Nasıl Kullanılır?



4 dakikalık okuma
December 28, 2018

Evvela şunu söylemek gerekir ki oluşturulan her bir nesne hafızada yer kaplar. Bazı nesneler var ki her bir defasında ayrı ayrı oluşturulmaya gerek yoktur. Örnek vermek gerekirse db connection nesnesini verebiliriz. Her bir istemcide bu nesneyi tekrar oluşturursak hafızadan ciddi manada yer iştigal etmiş oluruz ve veritabanımızı da boşu boşuna birden fazla connection oluşturarak meşgul ederiz. Kısaca sistemi yavaşlatmış oluruz.

İşte bu tür sorunları aşmak için “Singleton” tasarım kalıbını kullanabiliriz. Böylece bir nesneyi sadece birkez oluşturmuş oluruz. Başka sınıflar o nesneyi tekrar oluşturmak istese de oluşturulmuş nesne üzerinde devam etmesini sağlarız.

Singleton tasarım kalıbı, “Creational” tasarım kalıbı kategorisine girer. Bu kategori(Creational) bir yada daha fazla nesnenin oluşturulması ve yönetilmesi ile ilgilidir.

Aşağıda genel bir singleton sınıf kalıbı var.

// General singleton class.
class Singleton {
  // Hold the class instance.
  private static $instance = null;
  
  // The constructor is private
  // to prevent initiation with outer code.
  private function __construct()
  {
    // The expensive process (e.g.,db connection) goes here.
  }
 
  // The object is created from within the class itself
  // only if the class has no instance.
  public static function getInstance()
  {
    if (self::$instance == null)
    {
      self::$instance = new Singleton();
    }
 
    return self::$instance;
  }
}

Yukarıdaki Singleton kalıbını incelersek:

Aslında statik metoddan yararlanıyoruz. Nesne yaratma hadisesi private yapılarak dışarıdan engelleniyor. Sadece o nesneyi içeride public static function getInstance() metodu içerisinde yapabiliyoruz ve bu metodda statik metod.

Bu metodun içerisine baktığımızda:

  public static function getInstance()
  {
    if (self::$instance == null)
    {
      self::$instance = new Singleton();
    }
 
    return self::$instance;
  }

Eğer bu sınıf ilk kez oluşturuluyorsa bir kez oluşturacağız ondan sonra oluşturulan nesne üzerinden diğer nesnelerin kullanılmasını sağlayacağız.

Aşağıdaki örneklerde görüldüğü gibi:

// All the variables point to the same object.
$object1 = Singleton::getInstance();
$object2 = Singleton::getInstance();
$object3 = Singleton::getInstance();

$object1 ile birkez sınıf oluşturuluyor ve $object2 , $object3 ‘te $object1 ile oluşturulmuş nesne tekrar kullanılacak. Ayrıyeten oluşuturlmayacak.

Aşağıdaki şemada “Singleton” tekniği ile oluşturulmuş ve oluşturulmamış sınıfların davranış örneklerini göreceksiniz:

Singleton

Gerçek Hayatta kullanım örneğine bakalım:

// Singleton to connect db.
class ConnectDb {
  // Hold the class instance.
  private static $instance = null;
  private $conn;
  
  private $host = 'localhost';
  private $user = 'db user-name';
  private $pass = 'db password';
  private $name = 'db name';
   
  // The db connection is established in the private constructor.
  private function __construct()
  {
    $this->conn = new PDO("mysql:host={$this->host};
    dbname={$this->name}", $this->user,$this->pass,
    array(PDO::MYSQL_ATTR_INIT_COMMAND => "SET NAMES 'utf8'"));
  }
  
  public static function getInstance()
  {
    if(!self::$instance)
    {
      self::$instance = new ConnectDb();
    }
   
    return self::$instance;
  }
  
  public function getConnection()
  {
    return $this->conn;
  }
}

Connectiondb’nin oluşturulup oluşturulmadığını kontrol ediyoruz. Oluşturulduysa aynı bağlantı nesnesi tekrar hizmetimize sunuluyor. Ne kadar bağlantı nesnesi kullandığımız önemli değil. Lütfen aşağıya bakın:

$instance = ConnectDb::getInstance();
$conn = $instance->getConnection();
var_dump($conn);

$instance = ConnectDb::getInstance();
$conn = $instance->getConnection();
var_dump($conn);

$instance = ConnectDb::getInstance();
$conn = $instance->getConnection();
var_dump($conn);

Yukarıdaki 3 bağlantı örneği de aynı sonucu verecektir. Singleton(tek nesne) tasarım kalıbı, bir sınıfın tek bir örneğini almak için kullanılır. Amaç oluşturulan nesneye global erişim noktası sağlamaktır. Sistem çalıştığı sürece ikinci bir örnek oluşturulmaz, böylelikle istenen nesnenin tek bir defa oluşturulması garanti altına alınacaktır. Singleton nesneler ilk çağırıldıklarında bir kere oluşturulurlar ve sonraki istekler bu nesne üzerinden karşılanır. Yukarıdaki örnek gibi.

Şimdi bir de Singleton tasarım kalıbını kullanmadan yukarıdaki veritabanı bağlantı sınıfını tasarlayalım:

// Connect db without a singleton.
class ConnectDbWOSingleton {
  private $conn;
  
  private $host = 'localhost';
  private $user = 'db user-name';
  private $pass = 'db password';
  private $name = 'db name';
   
  // Public constructor.
  public function __construct()
  {
    $this->conn = new PDO("mysql:host={$this->host};
    dbname={$this->name}", $this->user,$this->pass,
    array(PDO::MYSQL_ATTR_INIT_COMMAND => "SET NAMES 'utf8'"));
  }
   
  public function getConnection()
  {
    return $this->conn;
  }
}

Şimdi her bir nesne oluşturmada yeni bir veritabanı bağlantısı tanımlamış oluyoruz. Böylece hem hafızadan gidiyor hem de veritabanında birden fazla bağlantı oluşturmuş oluyoruz:

$instance = new ConnectDbWOSingleton();
$conn = $instance->getConnection();
var_dump($conn);
 
$instance = new ConnectDbWOSingleton();
$conn = $instance->getConnection();
var_dump($conn);
 
$instance = new ConnectDbWOSingleton();
$conn = $instance->getConnection();
var_dump($conn);

Yukarıdaki kod sistemimizi hem yavaşlatacak hem de hafıza kullanımını artıracaktır.


Etiketler: