LINUX.ORG.RU

Зачем нужен синглетрон?

 ,


1

3

Зачем нужен шаблон «проектирования» синглетрон? Почему про него везде пишут, почему я его ни разу не применял? Зачем он нужен, для чего?

class OneInstance{

   static $ya = null; 
    
   static function factory(){
       if(!self::$ya){
            return self::$ya = new self;       
       }else{
           return self::$ya;
       }
   }

}  

★★★★

Ответ на: комментарий от Deleted

неймспейсы для конфигов и мелочевки? ок

Deleted
()

синглетрон

улыбнуло)

anonymous
()
Ответ на: комментарий от resurtm

А что предложишь взамен не хочу услышать про DI когда мне нужен только один инстанс http request/ sql connection / и т.д на всё приложение?

Lancelot
()
Ответ на: комментарий от Deleted

rj45: static? не, не слышал

ZweiStein: Пространаства имён? Не, не слышал.

И смешно и грустно смотреть на такой стёб. Кичиться знанием элементарных вещей и засорять обсуждение - не от большого ума...

vinvlad ★★
()

В жопу синглтоны. Мешают тестированию, создают ложное впечатление правильной архитектуры («я у мамы дизайнер паттернов»). Сам по себе примитив «синглтон» может быть полезен только в качестве этюда, особенно с учетом многопоточности. На практике это антипаттерн, даже если это случай «есть железка, которая может быть только одна, бла бла бла». Никогда не надо забывать, что конфигурирование сущностей должно быть упорядоченным, а юнит-тестирование - простым.

Deleted
()
Ответ на: комментарий от resurtm

Нет, с DI всё в порядке, просто хотел чего-то другого

Lancelot
()
Ответ на: комментарий от resurtm

Чем собственно говоря DI плох?

DI не имеет прямого отношения к данной теме - это из другой оперы.

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

vinvlad ★★
()
Ответ на: комментарий от slapin

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

Deleted
()
Ответ на: комментарий от vinvlad

DI не имеет прямого отношения к данной теме - это из другой оперы.

DI/IoC как раз таки в том и помогают, чтобы не юзать антипаттерны вроде синглтона.

resurtm ★★★
()
Последнее исправление: resurtm (всего исправлений: 1)
Ответ на: комментарий от resurtm

DI/IoC как раз таки в том и помогают, чтобы не юзать антипаттерны вроде синглтона.

У всех ругателей синглтона какое-то черно-белое представление о шаблонах - этакий суровый догматизм. А реальность... она окрашена в полутона и в разные цвета.

К тому же, судят они исключительно исходя из своего персонального опыта, который заведомо не универсален, - а то и просто с чужих слов. Это как в старом студенческом анекдоте про студента, обезьяну и банан - «чего думать - прыгать надо...»

Тот же DI запросто можно использовать в сочетании с синглтоном - их в принципе нельзя противопоставлять.

vinvlad ★★
()
Ответ на: комментарий от Lancelot

Но зачем?

Допустим, вы реализуете не какое-то супер-корпоративное приложение или какой-нибудь монстровый фрэймворк, в создании и «допиливании» которого участвуют десятки совершенно разных людей - нет, вы делаете приложение, расчитанное на реализацию одним человеком (больше и не требуется). При этом вам хочется, чтобы код был максимально самодокументируемым и надёжным в плане сопровождения - простое такое, естественное желание...

Ну так, если программная логика подразумевает наличие только одного экземпляра объекта, реализующего какой-то конкретный интерфейс, то почему бы не «зашить» это требование непосредственно в программный код путем использования синглтона? Когда код перейдет на сопровождение другому программеру, тот сразу увидит это ограничение и у него не возникнет лишних вопросов.

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

Вот совершенно простой пример, базирующий на обычном здравом смысле. Если такие вещи проскакивают мимо сознания, то я даже не знаю, что сказать...

vinvlad ★★
()

Разве Синглтон - это шаблон проектирования?!

Это наверное как сказать что колесо - шаблон проектирования, а не часть например паттерна - четырёхколёсный легковой автомобиль или 2х колёсная тачка для перевозки песка ну или на худой конец мацацыкл для хоног по грязи.

Про одноколёсные лисапеды клоунов в цирке наверное вообще мало кто помнит.

Ну про паттерны грузовиков - там их набор весьма велик.

Serg_HIS
()

Для начала рассказал бы стек технологий.

А это уже ближе именно к паттерну проектирования.

Ты бы ещё назвал статик объекты паттерном проектирования ;)

Serg_HIS
()
Ответ на: комментарий от vinvlad

О приложениях, где требуются сложные SQL-запросы и, естественно, требуется оптимизация этих самых запросов. Такие вещи сильно привязаны к конкретной СУБД-шке, поэтому об автоматическом переносе кода на другую СУБД-шку речи в принципе не идет. Отсюда и отказ от ORM, поскольку в случае ORM вы вообще теряете контроль над SQL-кодом и можете заполучить какую-то чужую, усредненную и заведомо неэффективную реализацию, которая будет приемлемо работать только на небольших тестовых данных (религия здесь ни при чем).

Почему? Ну почему люди так любят делать все наполовину? Откуда это маниакальное стремление «перепрыгивать пропасть в два прыжка»?

vinvlad, вот лично тебя что толкает на этот подвиг?

Ладно, первый шаг — ORM не нужен, поскольку [тут обоснование]. И что ты предлагаешь вместо? «А давайте сделаем кучу запросов и утрамбуем их в суперпупермега класс, который реализуем как синглтон. Ах, да! У нас же суперпупер-приложение, поэтому заоптимизируем-ка эти запросы по самый небалуй, ведь мы используем все возможности выбранной СУБД на 200%.

На самом деле нет, не используем. В этом месте ты испугался, остановился и начал городить свой собственный „ORM“. То есть, свалился в пропасть, и второй шаг тебе уже не сделать.

А всего-то надо было на сторону СУБД вынести логику доступа к данным — все эти супероптимизированные запросы. Конечно, спроектировать систему хранимых (желательно так, чтоб это была именно система, а не хаотичный набор) все же придется. Надо рассказать, что в этом случае получаешь в замен?

anonymous
()
Ответ на: комментарий от anonymous

что ты пытаешься у него узнать? :) он просто не умеет программировать, вот и всё.

anonymous
()
Ответ на: комментарий от bodqhrohro_promo

Разработчики стандарта и за инкапсуляцию долго визжали, да так, что нарушать её при надобности пришлось через жопу рефлексию

Вот что ты за фигню пишешь?

Да весь твой пост вообще.

Языки программирования сделаны чтобы на них программировать. А не для того чтобы такие крикуны как ты кричали что всё не так.

Вот дашь тебе раздолье и возможности - орёшь ту сразу! «Блин я могу такой код написать с такими гибкостями и раздольями, что докажу другим, что смогу яички(ногу) себе отстрелить наспор»

Не дашь тебе возможностей чтобы ты смог так вывернуться - опять же! «Блин тут никакой гибкости нет! Я вот хотел бы сразу стрелять через свой рот сквозь свой пищевод в пролетающие инопланетные корабли, хотя так и не органично, но так тоже нужно мочь!»

На таких как ты не угодишь. Тебя легче застрелить чем тебе угодить :)

Serg_HIS
()
Ответ на: комментарий от anonymous

Ладно, первый шаг — ORM не нужен, поскольку [тут обоснование].
И что ты предлагаешь вместо? «А давайте сделаем кучу запросов и утрамбуем их в суперпупермега класс, который реализуем как синглтон.

Когда я выложил первый пост в эту тему, я просто привел пример, как можно реализовать класс-обертку вокруг какого-то из стандартных PHP-расширений, относящихся к работе с БД. Например, при реализации REST API, где задействована предварительно выбранная реляционная база данных. Имелось в виду, что обращение к БД требуется не во всех запросах, а если требуется - то может происходить в нескольких отдельных классах, реализующих уровень модели. Тут получение класса-драйвера работы с БД с помощью синглтона вполне по делу.

Ко мне прикопались по этому поводу, что это потянет за собой тридцать каких-то других синглтонов, и вообще я не прав, что собираюсь работать с реляционной СУБД на уровне SQL, поскольку это затрудняет миграцию приложения на СУБД-шку другого производителя ) Типа, придется частично менять программный код - а это не хорошо ).

Вообще говоря, бывают конечно случаи, когда можно и перескочить без особых изменений. Типа, у вас две-три таблички и не используются какие-то специфичные типы данных и расширения СУБД конкретного производителя - не выходим за рамки SQL-стандартов.

Но в реальности, если говорить о чем-то более серьезном, так не бывает. Единственный горячо продвигаемый в массы «шаблон» в таком случае - это отказ от использования SQL и переход к использованию ORM. Типа, тогда не надо менять код. Поскольку это может повлечь за собой быструю смерть проекта, как только он столкнется с реальным объемом данных, я позволил себе высказался на этот счет.

Как выполнять миграцию на СУБД-шку другого производителя - это в большой степени зависит от реально имеющегося кода. Иногда можно просто сделать дополнительный helper-класс, в который зашить какие-то различия SQL-запросов и типов данных в контексте разных CУБД. Но если менять придется большое число запросов, то может получиться, как вы правильно заметили, монстрятина - проще будет просто переписать весь код уровня модели и поддерживать несколько отдельных реализаций или отказаться от одной из них. Об этом я сказал чуть позже в примечании.

Другой вариант - это изначально запроектировать внутри модели промежуточный уровень-аналог набора хранимых процедур (какой-то набор классов), в который запрятать все SQL-ки. Тогда изменения коснутся только этого уровня. Ну и походу дела его можно портировать - там, где это имеет смысл - в реальные хранимые процедуры. Вот только для такого проектирования нужны профи, денежные ресурсы и ресурсы времени, чего не всегда хватает.

В проекте с хорошим финансированием - да, это самый оптимальный подход. Ну а если это какой-то малобюджетный стартап, то тут разумнее просто изначально выбрать подходящую СУБД-шку, а всё остальное оставить на потом. Появятся деньги и время - появится и новая, более правильная версия.

Это так... лирическое отступление, не имеющее прямого отношения к данной теме. Но раз уж пристали... ))

vinvlad ★★
()
Ответ на: комментарий от vinvlad

это отказ от использования SQL и переход к использованию ORM

Я другой анонимус, и у меня вопрос - нафига? Если тебе нужны сложные, под движок заточенные, нативные запросы, все ORM, которых я знаю, поддерживает выполнение RAW запроса. Главное к такому не привыкать, хорошо спрятать, чтоб глаза не мозолить, и пометить «тут у нас срут, но так надо...».

anonymous
()
Ответ на: комментарий от vinvlad

Мне ничего не мешает делать так:

class Di {

	protected $registry = []; 
	
	public function __set(string $name, Closure $value) {
		// ...
	}

	public function __get(string $name) {
		// ...
	}
}

$di = new Di();

$di->db = function() {
	return new DB();
}
Я могу для контейнера определить любую логику хранения объектов (один инстанс или на каждый вызов новый инстанс), единственное о чём нужно подумать, это как контейнер передавать внутри приложения. Сильно это сложнее реализации Singleton? Нет. Про плюсы использования DI и минусы Singleton на каждом заборе уже написано, но опять же выбор за разработчиками, лично у меня подход с использованием DI не вызывает чувства, что я делаю что-то не так, чистые руки, чистая карма

Lancelot
()
Ответ на: комментарий от anonymous

Если тебе нужны сложные, под движок заточенные, нативные запросы, все ORM, которых я знаю, поддерживает выполнение RAW запроса. Главное к такому не привыкать, ...

А зачем тогда ORM, если ты собираешься использовать RAW-запросы? Только лишняя трата и заведомо неоптимальное (вообще не понять какое) использование ресурсов сервера...

Если ты имеешь дело с РЕЛЯЦИОННОЙ СУБД и достаточно большими данными, к этому как раз и надо привыкать - использовать SQL.

Вот как, к примеру, ты будешь анализировать план выполнения SQL-запросов, если у тебя перед глазами их вообще нет? - они скрыты где-то в недрах ORM. Без обид, но рассуждать о преимуществах ORM поверх RDBMS могут только люди, не понимающие, как работают СУБД-шки такого типа.

vinvlad ★★
()
Ответ на: комментарий от vinvlad

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

скрыты где-то в недрах ORM

Их несложно достать.

x3al ★★★★★
()
Ответ на: комментарий от Lancelot

Мне ничего не мешает делать так: ...

Ну и к чему городить весь этот код, когда тебе класс Di больше ни для чего не нужен в каком-то конкретном приложении? Не проще ли просто добавить static-метод в DB-класс?

Какие-то универсальные контейнеры не всегда нужны. Надо не о карме думать и слепо, как зомбик, воспринимать «заборные» тексты, а просто учиться использовать разные приемы и шаблоны программирования осмысленно - там, где они действительно несут какую-то пользу.

vinvlad ★★
()
Ответ на: комментарий от vinvlad

А зачем мне менять DB класс или любой другой и явно добавлять какую-то логику его создания в него же, когда я могу просто хранить его инстанс, это же удобнее.

Lancelot
()
Ответ на: комментарий от x3al

... и концентрироваться на производительности только того, что важно

ORM вообще не позволяет концентрироваться на производительности. ORM-ки, если и можно использовать, то только на небольших базах данных, где по фигу, как выполняются запросы.

Их несложно достать.

Их всегда надо иметь перед глазами при чтении и отладке исходного кода.

vinvlad ★★
()
Ответ на: комментарий от Lancelot

А зачем мне менять DB класс или любой другой и явно добавлять какую-то логику его создания в него же ...

У меня такое впечатление, что ты не читаешь (точнее, не воспринимаешь) чужие посты - основное их содержание проскакивает мимо твоего сознания - нет осмысленного восприятия. «Прыгаешь» и «прыгаешь»... Ты хоть название темы перечитай - мы ж здесь не контейнеры обсуждаем, а где и для чего полезен такой прием программирования как синглтон.

ЦИТАТА:

Possibly the simplest design pattern is the singleton, which is a way to provide one and only one object of a particular type. This is used in the Java libraries, ...

Правда, буквальный перевод фразы «design pattern» в отношении синглтона - это звучит слишком громко ) Это просто прием НАДЁЖНОГО программирования и повышения ЧИТАБЕЛЬНОСТИ исходного кода.

vinvlad ★★
()
Ответ на: комментарий от vinvlad

... для того, чтобы ухватить сознанием смысл таких слов, как НАДЕЖНОСТЬ ПРОГРАММИРОВАНИЯ и ЧИТАБЕЛЬНОСТЬ ИСХОДНОГО КОДА, нужно иметь достаточный опыт работы с чужими исходниками и хотя бы приблизительно представлять, на какие грабли может наступить программист при доработке чужого кода.

Если такого опыта нет...

vinvlad ★★
()
Ответ на: комментарий от Lancelot

... особенно когда у тебя всё завязано на глобальных переменных

А где ты увидел в синглтоне глобальную переменную? Есть приватное статическое свойство конкретного класса - это совсем другое. Или ты в принципе отрицаешь полезность статических свойств и методов? Это что, тоже где-то на «заборах» написано? )

Синглтон - это просто специфичная «фабрика класса».

vinvlad ★★
()
Ответ на: комментарий от Lancelot

... просто автор темы привел не совсем корректный фрагмент кода:

static $ya = null;
нужно заменить на:
private static $ya = null;

vinvlad ★★
()
Ответ на: комментарий от vinvlad

Потому что кто угодно может поменять его состояние в любой точке программы, он завистит от последовательности обращений к нему (если не readonly). Так же обычно его явно не передают через агругументы другим объектам, что несколько усложняет «читаемость» кода.

Lancelot
()
Ответ на: комментарий от Lancelot

Но вы можете делать как вам угодно, я не продаю религию, просто чаще всего целеобразно использовать IoC принципы при разработки приложений

Lancelot
()
Ответ на: комментарий от Lancelot

Потому что кто угодно может поменять его состояние в любой точке программы, он зависит от последовательности обращений к нему (если не readonly).

А если вы засунули объект в ваш контейнер, то всего этого нет? Те же проблемы ...

Естественно, сам синглтон-шаблон решает не все проблемы безопасного программирования, а только одну из - об остальных надо заботится внутри самого класса. И не всякий объект имеет смысл заворачивать в синглтон - для этой цели подходят долгоживущие объекты, связанные с какими-то внешними ресурсами: конфигурация, сетевые соединения, соединения с БД и пр. Вы же, надеюсь, не против таких глобальных объектов-потоков, как STDIN, STDOUT, STDERR?

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

Вот тут как раз вы глубоко не правы. Зачем его передавать через аргументы, если он по определению один? Кому надо, тот получит доступ к синглтону посредством обращения к его static-методу и сразу будет понятно, с каким объектом осуществляется работа. А вот если в исходнике объект прилетает через аргументы, то тут возникают непонятки: это зачем же его так передают, если есть механизм прямого доступа?

vinvlad ★★
()
Ответ на: комментарий от vinvlad

Во-первых: извини, но подробно отвечать не буду, отчасти потому что — Во-вторых — перед тем, как выше ругать тебя, я топик весь прочел (а ты тут немного повторяешься), и ругал тебя на основании твоих же вводных к задаче. Это просто для полноты картины.

Далее. В-самыглавных.

Другой вариант - это изначально запроектировать внутри модели промежуточный уровень-аналог набора хранимых процедур (какой-то набор классов), в который запрятать все SQL-ки.

Тут и есть подвох, аналоги писать НЕ НАДО! Надо писать хранимые. То есть, всю логику извлечения/сохранения данных вынести на сторону СУБД, благо даже пресловутый mysql уже давно может в хранимые, триггеры и т.п. Более того, если сделать это правильно, то получишь полноценный API, через который эти два модуля преспокойно будут общаться — да-да, модульность, она, родимая.

«Плюсы» тут очевидны (если нет — подскажу), а минусы ты сам выше уже исключил «осознанным выбором СУБД» и «максимальным использованием специфичных фич». По крайней мере, так я понял твои вводные.

Теперь, с чего, собственно, я и начал. Твоя главная ошибка именно в том, что направление ты выбрал верно, но в ходе решения остановился на полпути. Вот уперся в «синглтон» — и приехал. Именно за это ругательски ругаю тебя и всех, кто так делает. Решения такого рода надо доводить до конца.

Это так... лирическое отступление, не имеющее прямого отношения к данной теме. Но раз уж пристали... ))

Данная прямая тема — шлачище отстойнейшее рафинированое. В твоих же рассуждениях обнаружил работу мозга. А пристал ввиду очевидных недоработок. Не доверяешь ты своему мозгу, а это плохо, друг он тебе. Вот эту проблему я счел более важной.

anonymous
()
Ответ на: комментарий от anonymous

Я другой анонимус, и у меня вопрос - нафига? Если тебе нужны сложные, под движок заточенные, нативные запросы, все ORM, которых я знаю, поддерживает выполнение RAW запроса. Главное к такому не привыкать, хорошо спрятать, чтоб глаза не мозолить, и пометить «тут у нас срут, но так надо...».

На тему SQL приведу конкретный пример из своего опыта. Я в свое время проработал нескольких лет в банковском секторе в качестве Oracle DBA и Unix-админа. Ну и в одном банке какое-то время наблюдал странную картинку: каждый день процедура закрытия операционного дня какого-то отдела занимала на Oraclе 3 часа ) - все жутко бурчали, но чего-то дельного добиться от разработчиков из Питера не могли. Ребятишки, видимо, прогнали тестики на небольших данных и со спокойной совестью спихнули все это дело Заказчику. В конце концов это дело достало — решили разобраться самостоятельно. Запустили оракловый монитор, вычислили SQL-запрос, который так долго пахал и нашли его в исходниках - благо, до ORM тогда еще светлые умы не додумались :) Глянули имеющиеся индексы, добавили в SQL-ку хинт, чтобы цеплялся нужный индекс, и всё стало считаться за три минуты.

Представьте, если бы там всё было написано с использованием ORM — так бы люди и мучались...

vinvlad ★★
()
Ответ на: комментарий от Lancelot

взамен

$_dbc = new DBConnection(...);
function getConnection()
{
    global $_dbc;

    return $_dbc;
}

Для ленивого коннекта можно поюзать static взамест global. Это синглтон?

deep-purple ★★★★★
()
Ответ на: комментарий от vinvlad

А зачем приватный конструктор?

И не надо рассказывать про инкапсуляцию. Отнаследуемся от твоего синглтона и создадим второй экземпляр соединения с БД. Свинья грязи найдет, какие бы ты приватности не описывал.

deep-purple ★★★★★
()
Ответ на: комментарий от hobbit

конфигурация программы - чуть ли не единственный пример, где оправдан глобальный объект.

Возможен вариант, что ВСЕ данные будут глобально доступны. Я такое видел. Чела, начинающего пыхера, поносили за то что у него всё (вообще всё, не только конфиг) в одном большом многомерном массиве, который менялся в рантайме, поносили что так нельзя и все такое. Но на его вопрос «почему так нельзя» никто внятно не ответил. Причем у него там не было ни неймспейсов ни классов, только массив и функции. И оно работало.

deep-purple ★★★★★
()
Ответ на: комментарий от anonymous

Я другой анонимус, и у меня вопрос - нафига? Если тебе нужны сложные, под движок заточенные, нативные запросы, все ORM, которых я знаю, поддерживает выполнение RAW запроса.

По секрету собрату-анонимусу: ORM это не про генерацию запросов, это про структуру БД, модель данных. Именно это главная причина всех проблем ORM.

anonymous
()
Ответ на: комментарий от Lancelot

Потому что кто угодно может поменять его состояние в любой точке программы, он завистит от последовательности обращений к нему (если не readonly).

Это как-то отличает синглтон от «обычного» объекта?

SOLID

IoC

базворды-базвордики

anonymous
()

У синглтронов есть проблема - когда он сдохнет (это про C++) и когда родится (по коду это не понятно).

На связность влияет так же как и глобальная переменная.

На многопоточность не влияет. Это вопрос реализации класса который используется. Написали его потокобезопастным - что глобальная переменная, что синглтон будет потокобезопасным.

Тащемта синглТрон - это вопрос о методе коструирования/уничтожения объекта, и по большей части ниначе другое это не влияет.

Мое имхо - нихера это не антипатерн. Те не пригодилось т.к. повезло, можт еще пригодится.

anonymous
()
Ответ на: комментарий от anonymous

когда он сдохнет (это про C++) и когда родится

Узкое место, да. А нельзя ли экстерном сделать и по коду дела в нужном месте создать экземпляр один раз? Или это уже не синглтон?

deep-purple ★★★★★
()
Ответ на: комментарий от vinvlad

проработал нескольких лет в банковском секторе в качестве Oracle DBA

Ууу... Это многое объясняет. Было такое. Надо просто сказать себе: «Хранимые — это хорошо, главное не пихать туда бизнес-логику по примеру отдельных* криворуких оракел-девелоперов»

*) да, я верю, что существуют несрущие_в_хранимых оракел-девелоперы.

anonymous
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.