Одинак (Singleton)

Аналогія із реального життя

У підрозділу може лише один керівник. Він бере участь завжди, коли потрібно. І тут керівник і є одиночкою.

Короткий опис

Паттерн гарантує, що у додатку існуватиме лише один екземпляр цього класу.

Вікіпедія

Шаблон "Одинак" дозволяє обмежувати створення класу єдиним об'єктом. Це зручно, коли для координації дій у рамках системи потрібно, щоб об'єкт був єдиним у своєму класі.

Часто патерн Singleton використовується в коннектах до зовнішніх сервісів, але за деякими виданнями вважається антипаттерном, тому не слід ним зловживати. Використовувати його потрібно уважно, оскільки «Singleton» додає код глобальний стан і тому якщо змінити клас його використовує, то може знадобитися рефактор всіх місць його виклику. При використанні одинаки додаток стає сильно пов'язаним (tightly coupled) і ускладнює створення прототипів (mocking).

Класичний приклад

class Singleton
{
    private static $instance = null;
    private function __clone() {}
    private function __construct() {}

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

    public function test()
    {
        var_dump($this);
    }
}

Приклади
$Object = Singleton::getInstance(); // Отримання об'єкта
// Висновок буде однаковим, тому що існує лише один екземпляр
$Object -> test();
Singleton::getInstance() -> test();
// Спроба створити додатковий екземпляр призведе до помилки
$Object2 = New Singleton(); // Fatal error: Call to private Singleton::__construct() from invalid context
$Object3 = clone $Object; // Fatal error: Call to private Singleton::__clone() from context ''

Приклад у вигляді абстрактного класу

abstract class Singleton
{
    /**
     * @return Singleton
     */

    final public static function getInstance()
    {
        static $instance = null;

        if (null === $instance)
        {
            $instance = new static();
        }

        return $instance;
    }

    final protected function __clone() {}
    protected function __construct() {}
}

class Foo extends Singleton {

}

class Bar extends Singleton {

}

var_dump(Foo::getInstance()); // object(Foo)[1]
var_dump(Bar::getInstance()); // object(Bar)[2]