Шаблони проектування: Singleton, Factory

76

Від автора: при розробці веб-додатків розробникам дуже часто доводиться вирішувати ті ж завдання, які з плином часу стали типовими. Тому для їх вирішення були придумані так звані шаблони проектування. У цьому уроці я хотів би розглянути два найбільш корисних і часто застосовуваних шаблону проектування.

Шаблони проектування: Singleton, FactoryШаблони проектування: Singleton, Factory

Введення

Як я і говорив вище, шаблони проектування вирішують типові завдання у веб-програмуванні. Але це не готове рішення однієї із задач, яку можна завантажити і застосувати у себе на практиці. Це — швидше за все метод, або ідея, як можна вирішити ту чи іншу задачу. Використання даних шаблонів допомагає значно прискорити процес розробки, так як Ви не витрачаєте час на винахід велосипеда, допомагає виробити загальну стратегію в побудові ієрархії в створюваному скрипті. Так само використання шаблонів проектування допомагає в документуванні роботи окремих вузлів Вашого веб-додатки. Так як, пояснюючи роботу ділянки коду, Ви можете сказати, що він побудований на базі шаблону Singtone, і обізнана людина відразу зрозуміє, в чому справа. Тому, знати, що таке шаблони проектування повинен кожен хороший розробник.

Звичайно, шаблонів придумано велика кількість і всі їх у даному уроці ми не зможемо розглянути. Але ми розглянемо два найбільш часто використовуваних, які можуть стати в нагоді у Вашій практиці.

Singleton

Давайте розглянемо код наступного файлу:

З’єднання з базою даних

«;
$this->db = new mysqli(‘localhost’,’root’,»,’minicms’);
if($this->db->connect_error) {
throw new DbException(«Помилка з’єднання «);
}
$this->db->query(«SET NAMES ‘UTF8′»);
}
public function get_data() {
$query = «SELECT * from menu»;
$result = $this->db->query($query);
for($i = 0; $i num_rows; $i++) {
$row[] = $result->fetch_assoc();
}
return $row;
}
}
$obj1 = new db();
$obj2 = new db();
$obj3 = new db();
?>

Як Ви бачите, в ньому описано нескладний клас, призначений для роботи з базою даних. Який, в конструкторі виконує з’єднання з базою даних. Тобто при створенні об’єкта виконується з’єднання з базою даних. Тепер, логічно було б, якщо один раз в скрипті буде створений об’єкт даного класу. І вся подальша робота зводилася до звичайного зверненню до цього об’єкту.

Але що буде, якщо створити кілька об’єктів даного класу? Як у нашому прикладі. У цьому випадку буде три рази викликаний метод конструктора, а разом з ним буде виконано три підключення до бази даних. Що не дуже добре в плані швидкодії і витрачених ресурсів. Це легко перевірити, якщо виконати цей скрипт в браузері:

Шаблони проектування: Singleton, Factory

Тому для подібних класів, необхідно забезпечити можливість створення тільки одного об’єкта і не більше.
Для рішення цієї задачі застосовується шаблон проектування Singleton. Даний шаблон гарантує, що у певного класу можна буде створити тільки один об’єкт.

Важлива умова роботи Singlton: необхідно закрити публічний доступ для конструктора класу, а також заборонити публічне клонування об’єктів. Для цього досить додати спецификатор доступу private для відповідних методів класу:

private function __construct() {
echo «

З’єднання з базою даних

«;
$this->db = new mysqli(‘localhost’,’root’,»,’minicms’);
if($this->db->connect_error) {
throw new DbException(«Помилка з’єднання «);
}
$this->db->query(«SET NAMES ‘UTF8′»);
}
private function __clone() {
}

Тепер опишемо метод реалізує шаблон Singleton (я наведу весь виправлений код класу):

З’єднання з базою даних

«;
$this->db = new mysqli(‘localhost’,’root’,»,’minicms’);
if($this->db->connect_error) {
throw new DbException(«Помилка з’єднання «);
}
$this->db->query(«SET NAMES ‘UTF8′»);
}
private function __clone() {
}
public function get_data() {
$query = «SELECT * from menu»;
$result = $this->db->query($query);
for($i = 0; $i num_rows; $i++) {
$row[] = $result->fetch_assoc();
}
return $row;
}
public function (i) {
return $this->i++;
}
}

Для роботи Singleton необхідні: статичний властивість $_ins (за замовчуванням містить у собі NULL) і статичний метод get_instance(). Властивість $_ins – буде зберігати в собі об’єкт класу db. Статичний метод get_instance() – гарантує створення тільки одного примірника об’єкта класу. Дивіться, так як ми домовилися, що у властивості $_ins буде міститися об’єкт класу. Значить насамперед у методі get_instance() ми виконаємо перевірку – якщо в даному властивості міститься об’єкт класу db, значить, ми повертаємо значення цієї властивості. В іншому випадку ми створимо об’єкт даного класу, запишемо його у властивість $_ins і повернемо його як результат відпрацювання даного методу.

Це і є реалізація шаблону Singleton. Тепер давайте подивимося, як створити об’єкт, використовуючи шаблон. Так як безпосередньо створити об’єкт класу вже не можна, тому як конструктор класу закритий. Створити об’єкт класу можна простим звернення до методу get_instance():

$obj1 = db::get_instance();
$obj2 = db::get_instance();
$obj3 = db::get_instance();

Давайте подивимося, що у нас вийшло:

Шаблони проектування: Singleton, Factory

Як Ви бачите, тепер конструктор класу викликається тільки один раз, тому що ми працюємо тільки з одним об’єктом класу. Для додаткової перевірки, можна викликати метод i(), який я додав для прикладу. Якщо ми ось таким чином викличемо кілька разів даний метод:

$obj1 = db::get_instance();
echo ($obj1->i());
$obj2 = db::get_instance();
echo ($obj2->i());
$obj3 = db::get_instance();
echo ($obj3->i());

На екрані ми побачимо наступне:

Шаблони проектування: Singleton, Factory

Це доводить, що ми працюємо з одним і тим же об’єктом класу db.

Fabric

Шаблон проектування Fabric – відповідає за створення об’єктів певних класів. Даний шаблон раціонально використовувати, коли необхідно реалізувати автоматичне завантаження файлів з класами і подальшим створенням об’єктів цих класів. А також коли у певного набору класів при створенні їх об’єктів, необхідно викликати додаткові методи, практично однакові для кожного з них. І що б для кожного класу не прописувати виклик одних і тих же методів. Зручно винести їх виклик в окремий клас і звертатися до нього як до посередника при створенні об’єктів. Отже, найпростіший приклад шаблону Fabric.

i = «True»;
}
}
class get {
public static function create($item) {
/////
///
return new test();
}
}
$o = get::create(‘str’);
var_dump($o);
?>

Наприклад, є якийсь клас test. Для створення його об’єкта, ми створюємо додатковий клас get, зі статичним методом create(), який створить і поверне об’єкт класу test(). При цьому після створення об’єкта в методі create(), можна викликати різні методи класу test, якщо звичайно вони потрібні за логікою роботи скрипта.

Наступний приклад – це вже більш реальний випадок. У даному прикладі ми створюємо механізм автоматичного завантаження файлів з потрібними класами.

i = «True»;
}
}
class example {
public function __construct() {
echo «
Це клас — «.__CLASS__;
}
public function init(){
$this->i = FALSE;
}
}
class get {
public static function create($class) {
if(file_exists(‘classes/’.$class.».php»)) {
include_once ‘classes/’.$class.».php»;
if(class_exists($class)) {
$o = new $class;
$o->init();
return $o;
}
}
}
}
get::create(‘test’);
get::create(‘example’);
?>

Наприклад, за логікою нашого скрипта, нам необхідно підключати класи test і example, які розташовані в окремих файлах. Для цього ми створюємо клас get, зі статичним методом create(). Параметром даний метод приймає ім’я класу, об’єкт якого потрібно створити. Класи test і example збережені у файлах імена, такі ж, як і імена класів. Тому, коли передається ім’я класу — метод create(), також передається ім’я файлу, в якому розташований даний клас. Далі залишається перевірити існування даного файлу і потрібного класу в ньому, підключити даний файл і створити його об’єкт. Знову ж можна викликати різні додаткові методи. У нашому прикладі додатковий метод – це метод init(). Давайте подивися в браузері, що у нас вийшло:

Шаблони проектування: Singleton, Factory

Третій приклад шаблону Fabric. Приміром, є наступна ієрархія класів:

color = $color;
echo $this->color.»
«;
}
}
class Toyota extends Car {
public function __construct($color) {
echo parent::__construct($color);
}
}
class Mazda extends Car {
public function __construct($color) {
echo parent::__construct($color);
}
}
class Ford extends Car {
public function __construct($color) {
echo parent::__construct($color);
}
}
?>

Знову ж класи дуже прості і створені тільки для прикладу. Дивіться є батьківський абстрактний клас Car, в якому описаний метод конструктора. І є три його нащадка класи Toyota, Mazda і Ford. Для створення об’єктів цих класів, ми створимо додатковий клас і метод посередник, який залежно від переданих аргументів буде створювати об’єкт одного з класів.

class get {
public static function create($type,$color) {
switch($type) {
case ‘Toyota’:
return new Toyota($color);
break;
case ‘Mazda’:
return new Mazda($color);
break;
case ‘Ford’:
return new Ford($color);
break;
}
}
}
$car = get::create(‘Ford’,’green’);
var_dump($car);

Як Ви бачите в цьому класі метод get() використаний звичайний умовний оператор switch(), який в залежності від значення параметра $type створює об’єкт потрібного класу. На екрані ми побачимо наступне:

Шаблони проектування: Singleton, Factory

Шаблон проектування Fabric якраз і показує, що шаблони це не готове рішення – це метод як можна організувати логіку і побудова ієрархії Вашого скрипта.

Це і все що я хотів показати Вам даному уроці. Всього Вам доброго і вдалого кодування!!!