This is an old revision of the document!
Реестр (Registry)
Хотелось бы начать с этого шаблона. Он немного выбивается из общего ряда, потому что не является порождающим, но в дальнейшем нам потребуется его знание. Итак, реестр – это хэш, доступ к данным у которого осуществляется через статические методы:
<?php
/**
* Реестр
*/
class Product
{
/**
* @var mixed[]
*/
protected static $data = array();
/**
* Добавляет значение в реестр
*
* @param string $key
* @param mixed $value
* @return void
*/
public static function set($key, $value)
{
self::$data[$key] = $value;
}
/**
* Возвращает значение из реестра по ключу
*
* @param string $key
* @return mixed
*/
public static function get($key)
{
return isset(self::$data[$key]) ? self::$data[$key] : null;
}
/**
* Удаляет значение из реестра по ключу
*
* @param string $key
* @return void
*/
final public static function removeProduct($key)
{
if (array_key_exists($key, self::$data)) {
unset(self::$data[$key]);
}
}
}
/*
* =====================================
* USING OF REGISTRY
* =====================================
*/
Product::set('name', 'First product');
print_r(Product::get('name'));
// First product
Нередко можно встретить реестры, реализующие интерфейсы ArrayAccess и/или Iterator, но на мой взгляд, это лишнее. Основное применение реестра – в качестве безопасной замены глобальным переменным.
Пул объектов (Object pool)
Этот шаблон, по сути, является частным случаем реестра. Пул объектов – это хэш, в который можно складывать инициализированные объекты и доставать их оттуда при необходимости:
<?php
/**
* Пул объектов
*/
class Factory
{
/**
* @var Product[]
*/
protected static $products = array();
/**
* Добавляет продукт в пул
*
* @param Product $product
* @return void
*/
public static function pushProduct(Product $product)
{
self::$products[$product->getId()] = $product;
}
/**
* Возвращает продукт из пула
*
* @param integer|string $id - идентификатор продукта
* @return Product $product
*/
public static function getProduct($id)
{
return isset(self::$products[$id]) ? self::$products[$id] : null;
}
/**
* Удаляет продукт из пула
*
* @param integer|string $id - идентификатор продукта
* @return void
*/
public static function removeProduct($id)
{
if (array_key_exists($id, self::$products)) {
unset(self::$products[$id]);
}
}
}
class Product
{
/**
* @var integer|string
*/
protected $id;
public function __construct($id) {
$this->id = $id;
}
/**
* @return integer|string
*/
public function getId()
{
return $this->id;
}
}
/*
* =====================================
* USING OF OBJECT POOL
* =====================================
*/
Factory::pushProduct(new Product('first'));
Factory::pushProduct(new Product('second'));
print_r(Factory::getProduct('first')->getId());
// first
print_r(Factory::getProduct('second')->getId());
// second
Одиночка (Singleton)
Наверное, один из самых популярных шаблонов. Как правило, его все запоминают первым. А ещё при поиске работы про него очень любят спрашивать на собеседованиях. Вот самый простой пример:
<?php
/**
* Одиночка
*/
final class Product
{
/**
* @var self
*/
private static $instance;
/**
* @var mixed
*/
public $a;
/**
* Возвращает экземпляр себя
*
* @return self
*/
public static function getInstance()
{
if (!(self::$instance instanceof self)) {
self::$instance = new self();
}
return self::$instance;
}
/**
* Конструктор закрыт
*/
private function __construct()
{
}
/**
* Клонирование запрещено
*/
private function __clone()
{
}
/**
* Сериализация запрещена
*/
private function __sleep()
{
}
/**
* Десериализация запрещена
*/
private function __wakeup()
{
}
}
/*
* =====================================
* USING OF SINGLETON
* =====================================
*/
$firstProduct = Product::getInstance();
$secondProduct = Product::getInstance();
$firstProduct->a = 1;
$secondProduct->a = 2;
print_r($firstProduct->a);
// 2
print_r($secondProduct->a);
// 2
Принцип синглтона прост, как пять копеек. Для того, чтобы обеспечить существование только одного экземпляра класса Product, мы закрыли все магические методы для создания экземпляра класса, клонирования и сериализации. Единственный возможный способ получить объект – воспользоваться статическим методом Product::getInstance(). При первом обращении класс сам создаст экземпляр себя и положит его в статическое свойство Product::$instance. При последующих обращениях, в рамках выполнения скрипта, метод будет нам возвращать тот же, ранее созданный, экземпляр класса.
Я добавил в класс открытое свойство $a, чтобы продемонстрировать работу одиночки. В данном примере можно увидеть, что и $firstProduct, и $secondProduct – есть ни что иное, как ссылка на один и тот же объект.