AGAVA partners programs http://agava.ru/partners/            

Название функции

             
Веб-курсы


Что это?

Оглавление

Основы
Основы основ

Практика
Гостевая книга
Простой сайт
Структура сайта (MVC)
Ядро (Light)
Ядро
Гостевая на SQL
Статические страницы
Модуль новостей
Система регистрации

Теория
Дебаггинг
Регулярные выражения
Введение в ООП
Паттерны проектирования

Репозитарий
BB-code
Почтовый класс
Пагинатор
Всякие полезности

Download
Полезные утилиты

Разное
Видеокурсы
Последние изменения
Вопросы и замечания сюда



Реклама

Диеты для похудения
Фреймворк Kohana. Обучение. Мануал на русском.
Качественная система обратного осмоса atoll от termostudio.ru






Паттерны проектирования

Синглетон (Singleton)

       
Фабрика (Factory)

       

Если вы взялись всерьёз программировать на ООП, готовьтесь к тому, что тут на каждом шагу грабли и вилы. Код более сложный и менее управляемый в силу своей запутанности, это приводит к куче логических ошибок, которые диагностировать очень трудно. Для того, чтобы избежать подобного рода недоразумений, а так же для того, чтобы как то упорядочить этот запутанный код, придуманы так называемые паттерны. Тоесть по русски - костыли, которые помогают не рухнуть сооружению, если оно строится несколькими подрядчиками или неумелыми гастарбайтерами.

Синглетон (Singleton)



Самым ярким и академическим примером является работа с базой данных.
Вот допустим у нас имеется класс для работы с БД.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
<?php

class dataBase 
{

    public function 
__construct() 
    {
        echo 
'Тут как бы коннект к базе<br>';
/*        mysql_connect( DBSERVER, DBUSER, DBPASSWORD );  
        mysql_select_db( DATABASE ); */        
    
}
    
    public function 
mysqlAssoc($query
    {
        echo 
'А тут как бы запрос: '$query;
/*        $res = mysql_query($query);  
        return mysql_fetch_assoc($res);    */    
    
}    
}

    
$db = new dataBase();
    
$db -> mysqlAssoc("SELECT * FROM `table`");



Все достаточно пристойно, как водится, в конструкторе осуществляется подключение (коннект) к серверу баз данных, дальше работаем с нужными методами.
Однако если разработчиков несколько, либо имеются провалы в памяти, не исключена ситуация, что объект будет инициализирован несколько раз в разных местах. Там, где потребуется работа с базой данных. Это приведет к тому, что конструктор тоже сработает несколько раз. А значит и соединений с сервером баз данных получится несколько, а это лишние телодвижения, перерасход памяти и неоправданные тормоза:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
<?php

class dataBase 
{

    public function 
__construct() 
    {
        echo 
'Тут как бы коннект к базе<br>';
/*        mysql_connect( DBSERVER, DBUSER, DBPASSWORD );  
        mysql_select_db( DATABASE ); */        
    
}
    
    public function 
mysqlAssoc($query
    {
        echo 
'А тут как бы запрос: '$query .'<br>';
/*        $res = mysql_query($query);  
        return mysql_fetch_assoc($res);    */    
    
}    
}

    
$db = new dataBase();
    
$db -> mysqlAssoc("SELECT * FROM `table`");
    
    
$db = new dataBase();
    
$db -> mysqlAssoc("SELECT * FROM `table`");    
    
    
$db = new dataBase();
    
$db -> mysqlAssoc("SELECT * FROM `table`");
/*
         РЕЗУЛЬТАТ
    
Тут как бы коннект к базе
А тут как бы запрос: SELECT * FROM `table`
Тут как бы коннект к базе
А тут как бы запрос: SELECT * FROM `table`
Тут как бы коннект к базе
А тут как бы запрос: SELECT * FROM `table`
*/    

Чтобы этого избежать, придуман хитрый способ - паттерн синглетон (Singleton). В переводе с английского - одиночка.
Вот мы в класс поместим статическую переменную $instance, а в неё метод getInstance() засунет экземпляр нашего класса.
Теперь этот экземпляр можно получить двумя способами, классическим и из статической переменной:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
<?php

class dataBase 
{
/*
* В эту переменную мы поместим единственный
* экземпляр класса, с которым и будем работать дальше.
*/
    
static private $instance;

/*
* А это метод, который и осуществит сие действо
*/
    
public static function getInstance() 
    {
        
self::$instance = new self;
        return 
self::$instance;
    }
    
/*        
* Ну а тут прочая белибирда
*/
    
public function __construct() 
    {
        echo 
'Тут как бы коннект к базе<br>';
/*        mysql_connect( DBSERVER, DBUSER, DBPASSWORD );  
        mysql_select_db( DATABASE ); */        
    
}
    
    public function 
mysqlAssoc($query
    {
        echo 
'А тут как бы запрос: '$query .'<br>';
/*        $res = mysql_query($query);  
        return mysql_fetch_assoc($res);    */    
    
}    
}

// Теперь объект можно получить так:
    
$db = new dataBase();
    
$db -> mysqlAssoc("SELECT * FROM `table`");    

// Или таким извратным способом:
    
$db dataBase::getInstance();;
    
$db -> mysqlAssoc("SELECT * FROM `table`");
    
/*
         РЕЗУЛЬТАТ
    
Тут как бы коннект к базе
А тут как бы запрос: SELECT * FROM `table`
Тут как бы коннект к базе
А тут как бы запрос: SELECT * FROM `table`
*/    

Обратите внимание, что инициализировали мы его ключевым словом self
1
2
3
4
5
6
7
8

//Это 
self::$instance = new self;

//тоже самое, что это
self::$instance = new dataBase();


На самом деле это не придает читабельности, дело на любителя. Просто нужно знать, что так можно.

Но вернемся к овину с нашими баранами. Для чего нужен такой выкрутас? А вот для чего. Если мы теперь в классе проверим на пустоту переменную $instance, то сможем узнать, вызывался ли этот класс методом getInstance(). И если уже вызывался, сделать оргвыводы и не дать вызвать его еще раз, выдав экземпляр из этой переменной.
А чтобы не дать вызвать класс обычным способом, объявим коструктор приватным. Тоесть запретим доступ к нему снаружи. Хватит того, что мы внутри класса уже набарагозили. Ну и таким же способом запретим клонирование на всякий случай.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
<?php

class dataBase 
{
/*
* В эту переменную мы поместим единственный
* экземпляр класса, с которым и будем работать дальше.
*/
    
static private $instance;

/*
* А это метод, который и осуществит сие действо
* за одно проверив существование объекта.
*/
    
public static function getInstance() 
    {
        if(empty(
self::$instance))  
            
self::$instance = new self;
        
        return 
self::$instance;
    }
    
/*        
* Ну а тут прочая белибирда с приватным конструктором
*/
    
private function __construct() 
    {
        echo 
'Тут как бы коннект к базе<br>';
/*        mysql_connect( DBSERVER, DBUSER, DBPASSWORD );  
        mysql_select_db( DATABASE ); */        
    
}
    
    public function 
mysqlAssoc($query
    {
        echo 
'А тут как бы запрос: '$query .'<br>';
/*        $res = mysql_query($query);  
        return mysql_fetch_assoc($res);    */    
    
}
    
    private function 
__clone() 
    {
        
/* Фиг вам. */    
    
}        
}

// Теперь получить объект можно только извратным способом:
    
$db dataBase::getInstance();;
    
$db -> mysqlAssoc("SELECT * FROM `table`");
    
// Несколько раз подряд
    
$db dataBase::getInstance();;
    
$db -> mysqlAssoc("SELECT * FROM `table`");
    
// А тут будет ошибка
    
$db = new dataBase();
    
$db -> mysqlAssoc("SELECT * FROM `table`");    
    
/*
         РЕЗУЛЬТАТ
    
Тут как бы коннект к базе
А тут как бы запрос: SELECT * FROM `table`
А тут как бы запрос: SELECT * FROM `table`

Fatal error: Call to private dataBase::__construct() from invalid context
*/                

Теперь сколько раз мы бы не получали объект в разных местах (других классах), соединение с базой будет произведено единожды.

Вот и весь синглетон. Теперь в любом месте мы можем получить единственный экземпляр класса. Он как бы попал в глобальное пространство. Это убережет от повторных инициализаций и пересечений, вызвав фатальную ошибку при попытке это совершить.

Паттерны проектирования

Синглетон (Singleton)

       
Фабрика (Factory)

       
Рейтинг@Mail.ru Рейтинг@Mail.ru Яндекс цитирования
irbis-team © 2009