Шаблоны проектирования в ООП PHP

Шаблоны проектирования



Шаблоны проектирования: Шаблоны проектирования



Шаблоны проектирования




Шаблоны проектирования - это инструкции, руководства для решения каких-то конкретных проблем


Рассмотрим шаблон проектирования (паттерн) - Singleton (одиночка), как самый простой для понимания и который можно использовать на практике очень часто.


Пример: Db Connector для подключения к базе данных.

Допустим, нам необходима работа с базой данных, соотетственно, есть класс для работы с базой данных, а от класса можно создавать объекты. И в конструкторе, когда мы работаем с классом Db, мы можем устанавливать соединение с базой данных. В этом случае, когда мы создадим два объекта данного класса, произойдет два соединения с базой данных. Поэтому встает задача как-то контролировать тот факт - создан ли объект класса Db и соответственно, не открыто ли было уже соединение с базой данных. Для того, чтобы это контролировать, как раз и существует паттерн Singleton, который не позволяет создать более одного объекта:

- если объект создан, тогда будет возвращен объект,

- если не создан, тогда объект данного класса будет создан и возвращен.


Суть паттерна заключается в том, что конструктор создается здесь приватным, а это значит, что от этого класса мы не сможем создать объект.

В классе А создадим приватный конструктор:


Файл A.php


-- файл A.php --

<?php
namespace app;

class A
{
// закрытый конструктор означает, что от этого класса мы не сможем создать объект
private function __construct()
{
}
}
?>




Если мы попытаемся создать объект класса A:

$a = new \app\A();

- получим ошибку: попытка вызова конструктора от класса А, который является приватным.

А приватные свойства и методы из вне не видны.


Для того, чтобы создать объект этого класса, существует закрытое (приватное) свойство $instance в котором и будет хранится объект данного класса. И создается метод, который часто называют getInstance(), он публичный и он статичный :


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



- здесь мы проверяем:


if (null === static::$instance)


- если у нас свойство $instance - пусто (в нем нет никакого объекта), тогда мы в это свойство запишем это самый объект:


static::$instance = new static();- создадим объект самого себя


(здесь используется static - он ссылается на сам себя, аналог - self)


return static::$instance;


- возвращаем объект. При последующему обращении к этому методу проверка уже не выполниться и мы сразу возвращаем этот объект.


Реализуем этот простейший паттерн в коде.


Файл A.php


-- файл A.php --

<?php
namespace app;

class A
{
// создадим закрытое статичное свойство $instanses
private static $instances ;

// создаем закрытый конструктор
private function __construct()
{
}

// создаем публичный статичный метод , что-бы к нему можно было обратиться из вне
public static function getInstance()
{
// проверяем:
// если объект текущего класса в нем не записан
if(self::$instances === null)
{
// тогда мы это запишем:
self::$instances = new self();
// - здесь мы обращаемся к текущему классу и содаем объект
// этого класса new self(), и записываем его в
// приватное свойство $instances
// То есть, мы в свойство $instances записываем объект new self() и ---
}
// --- возвращаем его
return self::$instances;
}
}
?>




В индексном файле мы не можем создать объект через new, но мы можем обратиться к классу А и вызвать метод getInstance(). Создадим и распечатаем объекты $a1 и $a2:


...
...
...

$a1 = \app\A::getInstance();
$a2 = \app\A::getInstance();

var_dump($a1);
echo '<br>';
var_dump($a2);

Выведет:
object(app\A)[4]
object(app\A)[4]



- получаем, что ($a1) и ($a2) - один и тот-же объект класса А (с номером - 4)

(С использованием Singleton у нас получается один и тот же объект)


Singleton можно использовать не только для класса Db, но и для других классов, от которых мы хотим создавать не более одного объекта. И соответственно, для всех зтих классов нам достаточно определить свойство $instances, приватный конструктор и метод getInstance().


Если мы в классе B продублируем код и в индексном файле создадим и распечатаем дополнительно объекты $b1 и $b2:


...
...
...

$b1 = \app\B::getInstance();
$b2 = \app\B::getInstance();

var_dump($b1);
echo '<br>';
var_dump($b2);

- то получим:
object(app\A)[4] - два одинаковых объекта класса А
object(app\A)[4]

object(app\B)[5] - и два объекта одинаковых класса B
object(app\B)[5]



Чтобы избежать дублирование кода используем трейты (traits).

Создадим в папке traits трейт TSingleton.


Файл TSingleton.php


-- файл TSingleton.php --

<?php
namespace app\traits;

trait TSingleton
{
// создадим закрытое статичное свойство $instanses
private static $instances;

// создаем закрытый конструктор
private function __construct()
{
}

// создаем публичный статичный метод , что-бы к нему можно было обратиться из вне
public static function getInstance()
{
// проверяем:
// если объект текущего класса в нем не записан
if(self::$instances === null)
{
// тогда мы это запишем:
self::$instances = new self();
// - мы обращаемся к текущему классу и содаем объект
// этого класса new self(), и записываем его в
// приватное свойство $instances
// То есть, мы в свойство $instances записываем объект new self() и ---
}
// --- возвращаем его
return self::$instances;
}
}
?>




В классе А используем - use TSingleton


Файл A.php


-- файл A.php --

<?php
namespace app;

use \core\traits\TSingleton; // подключаем TSingleton

class A
{
use TSingleton;
}
?>




Тоже самое делаем и для класса B


Файл B.php


-- файл B.php --

<?php
namespace app;

class A
{
use \core\traits\TSingleton; // путь подключаем здесь
}
?>




Файл index.php:


-- файл index.php --

<?php
use app\{BookProduct,NotebookProduct};
use core\interfaces\{IGadget,I3D};

error_reporting(-1);

require_once __DIR__ . '/vendor/autoload.php';

function debug($data)
{
echo '<pre>' . print_r($data, 1 ) . '</pre>';
}

function offerCase($product)
{
echo "<p>Предлагаем чехол для гаджета {$product -> getName()} </p>";
}

$book = new BookProduct('Три мушкетера', 20, 1000);
$notebook = new NotebookProduct('Dell', 1000, 'Intel' );

// Шаблоны проектирования ---------------------------------------------

// пытаемся создать объект:
//$a = new \app\A();
// - вызовет ошибку: идет попытка вызова конструктора от класса А,
// который является приватным, а приватные методы и свойства из вне не видны

// мы не можем создать объект класса через оператор new, но
// теперь можно создать объект класса через вызов метода getInstance() класса A
$a1 = \app\A::getInstance();
$a2 = \app\A::getInstance();

var_dump($a1);
echo '<br>';
var_dump($a2);
// - получаем, что ($a1) и ($a2) - один и тот-же объект класса А (с номером - 4)

echo '<br>';

$b1 = \app\B::getInstance();
$b2 = \app\B::getInstance();

var_dump($b1);
echo '<br>';
var_dump($b2);
// получаем, что ($b1) и ($b2) - один и тот-же объект класса В (с номером - 5)
?>
Получим:

object(app\A)[4] - два одинаковых объекта класса А
object(app\A)[4]

object(app\B)[5] - и два объекта одинаковых класса B
object(app\B)[5]





Содержание папки 17 ("Шаблоны проектирования"):


17-1



Мы избежали дублирование кода, создав трейт, который реализует паттерн Singleton, и подключив данный трейт в нужные классы, мы делаем эти классы реализующими паттерн Singleton.






Наверх Наверх