Одинак (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]