#ооп #php
Покажите на пальцах для чего нужен Singleton? class Singleton { protected static $instance; // object instance /** * Защищаем от создания через new Singleton * * @return Singleton */ private function __construct() { /* ... */ } /** * Защищаем от создания через клонирование * * @return Singleton */ private function __clone() { /* ... */ } /** * Защищаем от создания через unserialize * * @return Singleton */ private function __wakeup() { /* ... */ } /** * Возвращает единственный экземпляр класса * * @return Singleton */ public static function getInstance() { if ( is_null(self::$instance) ) { self::$instance = new Singleton; } return self::$instance; } public function doAction() { /* ... */ } } //usage Singleton::getInstance()->doAction(); Для чего писать так? Если можно написать вот так: class Singleton { public static function doAction() { /* ... */ } } Singleton::doAction(); Не проще, нет? %) Только не нужно давать ссылок на википедию и т.п. Всем спасибо! @knes, @ikoolik и @Nord001 — накинул вам по 25 очков за старание.
Ответы
Ответ 1
Синглтон нужен, чтобы точно знать, что у нас создан ОДИН объект данного класса. Классический пример - коннект к базе данных. Если куча скриптов внутри одного файла теребит БД в разных функциях, приходится заводить глобальную переменную соединения и постоянно проверять жива ли она, на случай если в данный момент идет первое подключение к БД. Синглтон же сам создает соединение, если оно еще не было установлено, либо просто возвращает готовую ссылку. Вам же требуется только вызвать его, уже ни о чем не заботясь: лишний раз базу не потревожат. Второй ваш пример плох тем, что можно насоздавать кучу объектов данного класса, которые не будут знать что происходит у остальных.Ответ 2
Синглтон - один из самых легких, но в то же время предельно значимых паттернов проектирования. Для чего он нужен, уже был дан ответ. Основная реализация показана вами, а вот плюшки каждый может привинтить свои. Так, например, в C++ можно создать отдельный шаблонный класс Singleton методом template, а далее уже делать из любого существующего класса синглтон. Ответ 3
Выше писали про БД, я так ипользую: Singleton::getInstance('main')->doAction(); Singleton::getInstance('no_main')->doAction(); Поясню. Есть 3 сайта. 4 БД. Из них 3 БД - это БД с инфой конкретного сайта, а четвёртая БД это данные пользователей, т.к. на всех 3х сайтах они одинаковы. Поэтому когда мне надо сделать запрос к БД пользователей я использую: Singleton::getInstance('main')->doAction(); если допустим нужны статьи, то: Singleton::getInstance('no_main')->doAction(); Тем самым у меня гарантированно будет не более 1 подключения к конкретной БД. По сути можно делать как вы и написали: Singleton::doAction(); Но если вам нужно будет какие-нибудь данные, то вы всё равно будете вызывать >getInstance() для того что бы обратиться допустим к БД.Ответ 4
Дело в том, что синглтон позволяет создать только один свой экземпляр. Соответственно все классы, в которых используется объект синглтона, используют один и тот же объект. С одними и теми же данными. Возьмем пример из ответа товарища @knes про соединение с БД. Если соединение с БД занесено в конструктор синглтона, то все классы использующие БД через синглтон используют одно и то же соединение. Еще пример: *** тут обьявление обычного класса `MyClass` с `private $a` и `getA(), setA()` *** $class1 = new MyClass(); $class2 = new MyClass(); $class2->setA(3); $class1->setA(5); echo $class2->getA(); //3 То же, если myClass - синглтон: $class1 = myClass::getInstance(); $class2 = myClass::getInstance(); $class2->setA(3); $class1->setA(5); echo $class2->getA(); //5 Все вышеизложенное - лишь наиболее понятная на мой взгляд иллюстрация механизма. Преимущества и недостатки синглтона - другая история.Ответ 5
class Singleton { private static $PrS='init private'; public static $PuS='init public'; public static function PrS($A=false) { if($A!==false) self::$PrS=$A; else return self::$PrS; } public static function PuS($A=false) { if($A!==false) self::$PuS=$A; else return self::$PuS; } } echo Singleton::PrS(); echo "\n"; echo Singleton::PuS(); // выведет init private // init public echo "\n -- \n"; $D = new Singleton(); echo $D->PrS(); // также выведет init private echo "\n"; // init public echo $D->PuS(); echo "\n -- \n SET them all!"; // А вот здесь Singleton::PrS('changed private'); // меняем переменные класса Singleton::PuS('changed public'); // используя статическую ссылку echo "\n"; // и попробуем проверить их из "созданного" класса (хотя это просто ссылка копия) echo $D->PrS(); // разумеется, выведет: changed private echo "\n"; echo $D->PuS(); // changed public скопируйте этот простой пример, запустите его, и вам будет понятно, что статический класс, вместе с его статическими же переменными не дублируется оператором new. Да хоть десять дублей наделайте - все равно - статические переменные останутся. Слово static для функции говорит о том, что в глобальной таблице при компиляции ей уже выделен адрес - жестко выделен. Так же и со статическими переменными - их адрес также статичен. А НЕстатические переменные (классы) не существуют в адресном пространстве, пока их не определят (оператором new). Обращаться некуда. Для статических адрес уже есть - и к нему (к переменной) можно обратиться всегда - someStaticClass::value Хотите использовать статический класс для работы с БД - заведите внутри приватную статическую переменную DB_handler. Надо работать с несколькими соединениями (несколько БД) - заведите еще по необходимости. Можно даже соорудить нечто статического массива. Почему нет? Появится необходимость слишком извернуться - перепишите класс. Т.е. копии статических классов вообще не различаются (при изготовлении их оператором new), пока в них не появится хотя бы одна НЕстатическая переменная. Правда, и после этого различаться они будут только этой НЕстатической переменной. Правда, при этом, управлять этой переменной уже получится уже только из изготовленного класса. Далее: public static function getInstance() { if ( is_null(self::$instance) ) { self::$instance = new Singleton; } return self::$instance; } Вот этот кусок кода как раз и возвращает копию ссылки на адрес статического класса Singleton. Это то же самое, что написать Singleton::(и там что-то) Вот об этом и был вопрос - "ЗАЧЕМ?". Ответ простой - да, НЕЗАЧЕМ :) Наверное, есть задачи, где надо заводить экземпляр класса Singleton, "...а вот если не было обращений (ну не потребовалось что-то), то ничего не заведется и все будет тихо и спокойно... А вот вроде как статический класс будет существовать даже тогда, когда он может не понадобиться... и ух, как страшно съест памяти..." В общем, как-то я не могу вот так с ходу придумать такой задачи, чтобы применять именно СОЗДАНИЕ классов вместо статических классов. И вот я например, тоже не вижу разницы между сложным Singleton наворотом и простым Singleton::doAction(). Вообще, статические классы (со статическими переменными) чрезвыйчано удобны еще и тем, что они предоставляют как бы "глобальные" переменные для любой области видимости. И хэндлер для БД тому яркий пример.
Комментариев нет:
Отправить комментарий