Сегодня мы начинаем довольно сложную тему шаблонов проектирования (Design patterns).
Шаблон проектирования по сути представляет собой подход к решению типовой задачи, который был неоднократно применен, признан среди специалистов, получил имя и довольно широкую известность.
Так в математике для нахождения корней квадратного уравнения в школе часто используют дискриминант. Никто не говорит: а давайте с вами попробуем использовать формулу, которая берет второй коэффициент со знаком минус, прибавляет или вычитает из этого коэффициента квадратный корень из суммы квадрата второго коэффициента и так далее... нет, все просто называют способ нахождения корней через дискриминант и имеют в виду одно и то же решение.
По такому же принципу работают и шаблоны проектироания.
В 1991 году Эрих Гамма, Ричард Хелм, Ральф Джонсон и Джон Влиссидес (John Vlissides) публикуют книгу Design Patterns — Elements of Reusable Object-Oriented Software.
В этой книге описаны 23 шаблона проектирования. Также команда авторов этой книги известна общественности под названием «Банда четырёх» (англ. Gang of Four, часто сокращается до GoF). До появления этой книги и предшествовавших ей работ ее авторов никто не формализовал и не использовал шаблоны проектирования. После выхода книги тема стала очень популярной.
Основные виды шаблонов проектирования:
- порождающие
- структурные
- поведенческие
- архитектурные
Порождающие шаблоны проектирования управляют процессом создания новых объектов. Применяются в случае, если классическое создание объекта не эффективно или противоречит общей задаче.
Есть 6 классических порождающих шаблонов проектирования:
- Простая фабрика
- Фабричный метод
- Абстрактная фабрика
- Строитель
- Прототип
- Одиночка
Структурные шаблоны проектирования предлагают варианты взаимного использования объектов, стуктурной их вложенности друг в друга, композиции объектов в более сложные объекты.
Есть 7 классических структурных шаблонов проектирования:
- Адаптер
- Мост
- Компоновщик
- Декоратор
- Фасад
- Приспособленец
- Заместитель
Поведенческие шаблоны проектирования, в отличие от структурных, не только определяют варианты взаимного использования объектов и сущностей, но и пытаются описывать способы их взаимодействия, их реализацию.
Десятка классических поведенческих шаблонов проектирования:
- Цепочка ответственности
- Команда
- Итератор
- Посредник
- Хранитель
- Наблюдатель
- Посетитель
- Стратегия
- Состояние
- Шаблонный метод
Выше перечислены лишь 23 классических шаблона проектирования от "Банды четырех". Помимо этих шаблонов есть масса других, в том числе как этих трех видов, так и архитектурные, а могут быть и еще каких-то дополнительных видов.
В этом уроке мы рассмотрим два довольно простых, но важных и интересных порождающих шаблона: Одиночка (Singleton) и и Простая фабрика (Simple Fabric)
###Шаблон проектирования Singleton
Одним из самых известных и популярных шаблонов проектирования в целом является шаблон Singleton.
Задача: существует класс и есть необходимость создать объект этого класса, но есть нюанс: необходимо проконтролировать, чтобы такой объект создавался только один. Второго такого объекта желательно не допускать. Эту задачу решает шаблон проектированя Singleton (Одиночка).
Классический пример такой задачи - подключение к базе данных. Каждое подключение к базе занимает место в памяти и требует времени для создания и удаления. Для одного, двух, пяти, десяти, сотни запросов к базе достаточно иметь всего лишь одно подключение. Чтобы избежать большого количества объектов подключения к базе данных, часто рекомендуется использовать Singleton.
Для начала, создадим класс, который будет подключаться к БД:
<?php
class DB {
function __construct(){
$this->con = new mysqli("127.0.01", "root", "12345", "books");
}
}
$db = new DB();
print_r($db->con->query("SELECT title FROM books")->fetch_all());Итак, у нас есть класс, который в конструкторе подключается к БД, подключение работает и позволяет выполнять запросы к БД.
Ничего на данный момент не мешает нам создать второй объект и выполнить второе подключение к той же БД. Необходимо каким-то образом запретить создавать объекты этого класса. Применим наши знания принципов ООП и магических методов, а имено: ограничим доступ к конструктору объекта, добавив ему спецификатор доступа private.
После такого изменения мы не сможем создавать новые объекты. Естественно, мы так же потеряем возможность создавать тот самый единственный способ.
Единственный способ создавать объект (при помощи ключего слова new) - создавать объект внутри класса, т.е. в рамках какого-то метода. Но. Обычные методы класса мы запускаем только посредством объекта класса, который мы как раз и не можем создать.
Тут нам на помощь приходят статические методы и свойства. Как нам известно, статические методы принадлежат классу, а значит, могут работать с приватными свойствами и методами класса. С другой стороны, они не требуют объекта и работают напрямую с классом. Применим эту идею на практике:
<?php
class DB {
private function __construct(){
$this->con = new mysqli("127.0.01", "root", "12345", "books");
}
static public function getConnect(){
return (new self())->con;
}
}
$con = DB::getConnect();
print_r($con->query("SELECT title FROM books")->fetch_all());
...отлично. Применили на практике знания о статике, но мы все равно имеем возможность создавать несколько объектов, просто более сложным путем. Но тут уже все проще, нам достаточно каким-то образом проверять, создавали ли мы объект, и не позволять создавать новые.
Поскольку создание происходит в статическом методе, хранить информацию о том, что мы уже создавали объект, нам предстоит тоже в статическом свойстве, другие нам некуда писать.
class DB {
static $obj;
private function __construct(){
$this->con = new mysqli("127.0.01", "root", "12345", "books");
}
static public function getConnect(){
if(empty(self::$obj))
self::$obj = new self();
return self::$obj->con;
}
}
$con = DB::getConnect();
print_r($con->query("SELECT title FROM books")->fetch_all());Варианты хранить bool переменную или счетчик созданных объектов нам в данном случае не подходит, ведь наш метод должен не только не позволять создавать новые объекты, но и как-то позволять работать со старым. Будем сохранять этот объект. Мы практически завершили написание шаблона проектирования Singleton, остался только один момент - закрыть еще два возможных варианта создания объектов, а именно: десериализацию и клонирование:
<?php
class DB {
static $obj;
private function __clone(){}
private function __wakeup(){}
private function __construct(){
$this->con = new mysqli("127.0.01", "root", "12345", "books");
}
static public function getConnect(){
if(empty(self::$obj))
self::$obj = new self();
return self::$obj->con;
}
}
$con = DB::getConnect();
print_r($con->query("SELECT title FROM books")->fetch_all());Мы реализовали самый известный, простой и популярный шаблон проектирования Singleton. На всякий случай имеет смысл прочесть статью на тему минусов его применения на сайте troger.ru.
- Написать класс для работы с книгами в базе данных.
- Написать с нуля для него подключение к БД с использованием шаблона проектирования Singleton.
- Почитать про другие шаблоны проектирования как в "банде четырех", так и в других книгах (рекомендую книги авторов Мэтта Зандстры, Александра Швеца), почитать статьи по ссылкам:
