juan_gandhi: (Default)
[personal profile] juan_gandhi
Как-то я не врубался во вред синглтонов - пока не пришлось рефакторить одну и ту же апликацию, разнесённую по двум платформам методом копи-пейста. Всякая собака ссылается на синглтон. Будто нельзя в параметрах получить (di, т.е.)

Так я о чём? Да вот: синглтон класса - это примерно как поименованная общая область. Вот вам имя, вот вам инстанс, и делайте вы с этим что хотите.

Тьфу.

Так что осознал, да. Синглтоны не то что зло, а большая глупость, имеющая причиной отсутствие дизайна. Десяток синглтонов - и вот вам помойка. В добавок к которой возникает священное знание: чтобы сделать то-то и то-то, надо взять три таких-то синглтона (и передать их друг другу, во).

Date: 2010-02-11 01:11 am (UTC)
From: [identity profile] qehgt.livejournal.com
Синглтон такое же зло, как и глобальные объекты, да.

С такими же минусами и отсутствием плюсов.
(deleted comment)

Date: 2010-02-11 02:02 am (UTC)
From: [identity profile] qehgt.livejournal.com
Ленивая инициализация и синглтон - это ж разные вещи.

Разговор о том, что синглтоны добавляют неявных зависимостей между модулями, что в дальнейшем мешает развитию/использованию. К примеру, через синглтон реализован интерфейс logger'а ("а, что, удобно, из любого места можно можно информацию вывести"). Позже, когда разным модулям требуется выводить свой лог в _разные_ места, выясняется, что сделать это в нынешнем виде невозможно.

А передавали бы интерфейс -- проблемы бы и не возникло.
(deleted comment)

Date: 2010-02-11 02:24 am (UTC)
From: [identity profile] sab123.livejournal.com
Алиментарно обеспечить. Иметь явный кэширующий контекст.

Date: 2010-02-11 02:38 am (UTC)
From: [identity profile] itman.livejournal.com
http://ivan-ghandhi.livejournal.com/1237032.html?thread=11119400#t11119400
Вообще, кеширующий контекст - это какие-то странные слова. Но важно-то тут то, что описанною мною ситуация, это не совсем инициализация. Инициализация происходит раньше. То есть объект существует априори в единственном числе.

Date: 2010-02-11 03:34 am (UTC)
From: [identity profile] itman.livejournal.com
Зря я все-таки потер. Все-таки, это получается синглтон. Можно считать, что есть функция
GetFileOpenIfClose(int FileNumber)
В парадигме синглтона, это решается заведение синглтона на каждый файл. Код инициализации синглотона также открывает файл. И можно в двух словах объяснить, как кеширующий контекст поможет заменить синглтон?

Date: 2010-02-11 02:28 pm (UTC)
From: [identity profile] sab123.livejournal.com
Объект будет существовать не в глобальном виде а как часть другого явно передаваемого объекта. То есть, да, синглтон, но внутри своего пространства имен.

Что такое контекст - читать тут http://members.verizon.net/~babkin/tpopp/05exit.txt , в конце страницы.

Date: 2010-02-11 03:30 pm (UTC)
From: [identity profile] ivan-gandhi.livejournal.com
Гуд пойнт насчёт особой проблемы с синглтонами в многопоточных программах. Поди найди концы - и, соответственно, решение держать контекст гораздо более осмыслено.

Date: 2010-02-11 03:53 pm (UTC)
From: [identity profile] itman.livejournal.com
Это фабрика, ИМХО. Но внутри все равно должны быть синглтона. От них не убежать. Главное, это избавиться от вызов getInstance там, где от него можно избавиться.

Date: 2010-02-12 01:27 am (UTC)
From: [identity profile] sab123.livejournal.com
Нет-нет. Фабрика каждый раз создает новый объект, используя запомненные параметры для конструктора.

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

Date: 2010-02-11 03:37 am (UTC)
From: [identity profile] itman.livejournal.com
Зря я все-таки потер. Все-таки, это получается синглтон. Можно считать, что есть функция
GetFileOpenIfClose(int FileNumber)
В парадигме синглтона, это решается заведение синглтона на каждый файл. Код инициализации синглотона также открывает файл. И можно в двух словах объяснить, как передача интерфейса поможет заменить синглтон? Или Вы имеете в виду интерфейс в смысле COM-объектов? Но так ведь там все равно возникает проблема однократной инициализации объекта. Чем это не синглтон.

Date: 2010-02-11 04:13 am (UTC)
From: [identity profile] qehgt.livejournal.com
>как передача интерфейса поможет заменить синглтон?
Было:
void MyClass::foo()
{
   ... bla-bla
   OurCoolUtils::Logger::getInstance()->write("Finish bla");
   ... boo-boo
}

Стало:
MyClass::MyClass(........, ILogger* logger) 
  : .... logger(logger)
{
  ...
}

void MyClass::foo()
{
   ... bla-bla
   logger->write("Finish bla");
   ... boo-boo
}

Date: 2010-02-11 04:16 am (UTC)
From: [identity profile] qehgt.livejournal.com
В реальных программах, конечно, передаваётся ссылка или используется smart pointer.

Всё для того же - сэкономить время в будущем.

Date: 2010-02-11 05:03 am (UTC)
From: [identity profile] itman.livejournal.com
А, я понял. Вы не хотите, чтобы в коде везде был getInstance(). Это ИМХО очень правильный подход :-)
Но все равно придется написать:
MyClass SomeVar(...,OutCoolUtils::Logger::getInstance())

Или инициализировать OutCoolUtils::Logger глобально.

Date: 2010-02-11 05:08 am (UTC)
From: [identity profile] itman.livejournal.com
Только я, возможно, забыл сказать, что в вышеприведенной задачке нельзя инициализировать объект глобально. Потому что инициализации и переинициализация наступает уже после старта программы.

Date: 2010-02-11 02:37 am (UTC)
From: [identity profile] itman.livejournal.com
Хотя на самом деле описанная задача - это не инициализация в явном виде. Инициализация как раз может происходить в функции открытия. Риторический опрос про передачу интерфейса (откуда и куда), остается открытым.

Date: 2010-02-11 03:15 am (UTC)
From: [identity profile] anton-solovyev.livejournal.com
Ну, я не знаю, а какие-нибудь findViewById() и всевозможные lookup provider (или как там его в Neatbeans) намного лучше?

Так или иначе всегда оказывается какой-нибудь сервис из серии "а вот как бы мне тут получить reference на что-то такое очевидное, но без передачи параметров?"

Date: 2010-02-11 03:36 am (UTC)
From: [identity profile] itman.livejournal.com
А это разве не скрытый синглтон получается? findViewById должна инициализировать объект ровно один раз, а все остальные разы она должна возвращать ссылку на уже проинициилизированный объект.

Date: 2010-02-11 09:28 am (UTC)
From: [identity profile] gabaidulin.livejournal.com
В параметрах можно получить. Но singletone все равно нужен иногда. Это мощная семантическая конструкция. Самый типичный пример Сессия. Она должна быть, как правило, одна для каждого клиента(внутри она может быть даже физически реплицируема по кластеру, это не важно). Такую семантику лучше всего передает как раз Singleton. Чем на ваш взгляд можно также семантически точно заменить этот паттерн в java/c#/php/etc?

Date: 2010-02-11 07:06 pm (UTC)
From: [identity profile] vaddimka.livejournal.com
фабриками

Date: 2010-02-12 05:26 am (UTC)
From: [identity profile] fantaseour.livejournal.com
в php сессии вполне себе ложатся в DI:

Phemto имеет встроенные классы: Factory (по умолчанию), который всегда создает новый экземпляр объекта, Reused который отдает ссылки на один и тот же экземпляр, и Sessionable, который хранит экземпляр объекта в системной переменной PHP $_SESSION. Они все наследуют от базового абстрактного класса Lifecycle. Разработчики могут расширять эти классы...

http://h-type.com/filez/lj/articles/di/

Date: 2010-02-11 10:30 pm (UTC)
From: [identity profile] cema.livejournal.com
Что за di?

А вообще-то синглтон нужен, скажем, для описания конфигурации. Ну или где у нас логи лежат, такие вещи (тоже конфигурация). В каком-то смысле аспекты? (Могу путать, аспекты не знаю толком.)

Date: 2010-02-12 12:11 am (UTC)
From: [identity profile] ivan-gandhi.livejournal.com
DI = Dependency Injection.

Да, надо сказать, где логи лежат. И так дюжину различных вещей надо сказать. Потом передавать эти штуки друг другу.

Date: 2010-02-12 05:36 am (UTC)
From: [identity profile] fantaseour.livejournal.com
nb. я про php говорю, посколько на нем пишу, но и тут есть DI.

Меня как раз в этом месте и колбасило, я так и пользуюсь несколькими синглтонами -- конфиг, фабрика соединений к БД, Environment (GET, POST, SESSION), но ощущение того, что я в главный контроллер ака точка входа могу запихнуть чтение конфигов а потом все это передавать через DI пришло.

Я инстинктивно боялся методов в т.ч. и конструкторов с большим количеством параметров, а DI как раз поощряет такие списки параметров, поскольку заполняет их автоматически. Таким образом в удобстве по сравнению с синглтонами мы ничего не теряем.

Date: 2010-02-12 12:39 pm (UTC)
From: [identity profile] gabaidulin.livejournal.com
Вот конкретно про php напишу.

Разумеется я читал про DI и про IoC. Но "тащить" подобный контейнер или делать service locator мне не нравится по нескольим причинам.

1. Код становится менее читаемым.
2. Для php нету устоявшейся практики применения IoC и вообще я сомневаюсь, что есть грамотные имплементации. Например порт pico выглядит ужасно, синтаксис конфигурации ужасен.
3. Производительность. Reflection все еще очень медленный на php(в особенности "new" Reflection API).

Мы использовали подход, что все служебные вещи(типа singltone, abstract factory, accert и так далее) это как бы часть языка. У нас был хороший framework, в котором мы все это хорошо реализовали.

Программист, который садился писать приложение, писал его фактически не на php, а на onPHP :-)

То есть если ему нужен был класс, который инстанциируется лишь однажды на все приложение, то он просто наследовался от abstract singleton.

Вы ведь не используете DI для внутренних классов языка или библиотеки.

Конкретно с сессией пример.

Имплементация сессии врядли меняется в php.

То есть вы пишите класс SessionUtils например. Его методы будут обычными врапперами для session_* и все. Считайте этот класс частью языка.

С контроллерами тоже все просто. Если мы говорим про web, то на входе контроллера будет HttpReqeust. Он заполнется глобальными данными из _GET/_POST/_SESSION в Front Controller (если это MVC).

То есть мой поинт в том, что сложные IoC контейнеры и не нужны вовсе.
Для реализации обычно хватает DI через конструктор или сеттер.

Date: 2010-02-12 12:45 pm (UTC)
From: [identity profile] gabaidulin.livejournal.com
Да, про java. Сейчас как раз изучаю J2EE и в частности spring. Там подход как раз обратный.

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

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

Но такой подход сложнее.

Date: 2010-02-12 01:09 pm (UTC)
From: [identity profile] fantaseour.livejournal.com
Вы по моей ссылке все-таки сходите, я старался, переводил :) там как раз имлементация крайне лаконичная и весь смысл именно в сборке приложения из конфигов....

И автор, известный в общем-то -- Маркус Бейкер (aka lastcraft)

Date: 2010-02-12 01:20 pm (UTC)
From: [identity profile] gabaidulin.livejournal.com
Да, phemto выглядит получше, но когда я ковырял эту тему(начало 2007 вроде), то phemto не видел(не было?).

Но, привеликой разницы, писать ли:

...new Reusable(new Object))...

Object extends Singleton

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



Profile

juan_gandhi: (Default)
Juan-Carlos Gandhi

May 2025

S M T W T F S
    1 2 3
456 7 8 9 10
11 121314151617
181920 21 222324
25262728293031

Most Popular Tags

Style Credit

Expand Cut Tags

No cut tags
Page generated May. 24th, 2025 05:41 am
Powered by Dreamwidth Studios