О синглтонах

Pauel Pauel
Синоним слова синглтон будет "глобальная переменная". Уже лет 50 все книги-буквари по программированию пишут одно и то же : "Избегайте глобальных переменных". Люди действительно стали избегать — практически везде, где раньше были глобальные переменные, выросли синглтоны. Что интересно — все проблемы остались. Фактически, такой синглтон просто замыкает самые разные контексты и является ни чем иным, как способом управления депенденсами, негибким, проблемным и очень непредсказуемым.

Есть простой подход, который позволит понять, о чем идет речь — заменяем слово "синглтон" на "глобальная переменная" и смотрим, что же изменилось. Обычно речь про единственный экземпляр какого то типа. Но, извините, синглтон и единственный экземпляр это немного разные понятия. Синглтон требует, что бы была глобальная точка входа. Более того, должна решаться какая то проблема, например — долгая инициализация, засорение глобального неймспейса и тд.

Вобщем, получается так, что для паттерна Синглтон есть почти одно применение — глобальный объект навроде App.

Множество других применений как правило сильно искусственные. Например класс DataBase. Ну есть у приложения ровно одна база данных, и что с того ? что мешает создавать экземпляры по требованию ? Если технических проблем нет, то синглтонить класс для работы с базой мягко говоря очень странный подход.

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

Если ограничить применение Синглтона именно глобальным объектом App, то, внезапно, из этого можно извлечь целый ряд профитов. Например можно ввести просто адскую диагностику средствами REPL. А можно менять стратегии персистанса глобального состояния. Забрать у классов эту обязанность и переложить её на фремворк приложения — пусть он решает, где и как будет сохраняться состояние приложения и будет ли вообще сохраняться. Что же должно храниться в этом объекте ? Хранить нужно собтсвенно состояние, время жизни которого
1. равно времени жизни экземпляра приложения
2. больше времени жизни экземпляра приложения

Собственно всё.

23.06.14 13:05: Перенесено модератором из 'Блоги' — AndrewVK
dr. Acula
dr. Acula
22.06.2014 07:22
I>Синоним слова синглтон будет "глобальная переменная". Уже лет 50 все книги-буквари по программированию пишут одно и то же : "Избегайте глобальных переменных". Люди действительно стали избегать — практически везде, где раньше были глобальные переменные, выросли синглтоны. Что интересно — все проблемы остались. Фактически, такой синглтон просто замыкает самые разные контексты и является ни чем иным, как способом управления депенденсами, негибким, проблемным и очень непредсказуемым.
Т.е. ты за DI и прочие IoC, я правильно понял?

I>Есть простой подход, который позволит понять, о чем идет речь — заменяем слово "синглтон" на "глобальная переменная" и смотрим, что же изменилось. Обычно речь про единственный экземпляр какого то типа. Но, извините, синглтон и единственный экземпляр это немного разные понятия. Синглтон требует, что бы была глобальная точка входа. Более того, должна решаться какая то проблема, например — долгая инициализация, засорение глобального неймспейса и тд.

При чём тут неймспесы?

I>Вобщем, получается так, что для паттерна Синглтон есть почти одно применение — глобальный объект навроде App.

У кого получается? У тебя?
Это прекрасно.

I>Множество других применений как правило сильно искусственные. Например класс DataBase. Ну есть у приложения ровно одна база данных, и что с того ? что мешает создавать экземпляры по требованию ? Если технических проблем нет, то синглтонить класс для работы с базой мягко говоря очень странный подход.

А что, синглтон по требованию созать нельзя?

I>Вообще говоря, мой подход с паттернам примерно такой — сначала решить задачу, а потом переводить решение в код. Если на втором этапе возникают ассоциации с паттернами, то, как вариант, можно посмотреть варианты решения просто для уточнения деталей. Писать или не писать конкретный паттерн явно в коде это вообще дело десятое.

I>За употребление паттернов на первом этапе, то есть на стадии поиска и принятия решения, считаю, надо бить по рукам, головам, почкам и даже ниже пояса любыми способами — явными, неявными, прямыми, косвенными, симметричными, ассиметричными и тд и тд и тд.
Да-да, и тут ты на Белом Коне с шакой наголо.

I>Если ограничить применение Синглтона именно глобальным объектом App, то, внезапно, из этого можно извлечь целый ряд профитов. Например можно ввести просто адскую диагностику средствами REPL. А можно менять стратегии персистанса глобального состояния. Забрать у классов эту обязанность и переложить её на фремворк приложения — пусть он решает, где и как будет сохраняться состояние приложения и будет ли вообще сохраняться. Что же должно храниться в этом объекте ? Хранить нужно собтсвенно состояние, время жизни которого

I>1. равно времени жизни экземпляра приложения
I>2. больше времени жизни экземпляра приложения
Какой-то поток сознания...начали с паттерна, перешли к какой-то прикладной проблематике.

I>Собственно всё.

Ниачём.
Ждём срыва покровов с goto.
Ikemefula
Ikemefula
22.06.2014 07:51
Здравствуйте, dr. Acula, Вы писали:

I>>Синоним слова синглтон будет "глобальная переменная". Уже лет 50 все книги-буквари по программированию пишут одно и то же : "Избегайте глобальных переменных". Люди действительно стали избегать — практически везде, где раньше были глобальные переменные, выросли синглтоны. Что интересно — все проблемы остались. Фактически, такой синглтон просто замыкает самые разные контексты и является ни чем иным, как способом управления депенденсами, негибким, проблемным и очень непредсказуемым.

DA>Т.е. ты за DI и прочие IoC, я правильно понял?

Я не знаю, что значит "за DI и IoC". Самый интересный вариант IoC на мой взгляд это использование лямбда-выражений в таких вещах, как Linq в .Net или Stream в Джава.

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

I>>Есть простой подход, который позволит понять, о чем идет речь — заменяем слово "синглтон" на "глобальная переменная" и смотрим, что же изменилось. Обычно речь про единственный экземпляр какого то типа. Но, извините, синглтон и единственный экземпляр это немного разные понятия. Синглтон требует, что бы была глобальная точка входа. Более того, должна решаться какая то проблема, например — долгая инициализация, засорение глобального неймспейса и тд.

DA>При чём тут неймспесы?

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

I>>Множество других применений как правило сильно искусственные. Например класс DataBase. Ну есть у приложения ровно одна база данных, и что с того ? что мешает создавать экземпляры по требованию ? Если технических проблем нет, то синглтонить класс для работы с базой мягко говоря очень странный подход.

DA>А что, синглтон по требованию созать нельзя?

Можно, только зачем ? Ответь на вопрос — какую проблему ты решаешь, делая класс базы данных синглтоном ?

I>>1. равно времени жизни экземпляра приложения

I>>2. больше времени жизни экземпляра приложения
DA>Какой-то поток сознания...начали с паттерна, перешли к какой-то прикладной проблематике.

Именно так и было задумано.
dr. Acula
dr. Acula
22.06.2014 08:11
I>>>Синоним слова синглтон будет "глобальная переменная". Уже лет 50 все книги-буквари по программированию пишут одно и то же : "Избегайте глобальных переменных". Люди действительно стали избегать — практически везде, где раньше были глобальные переменные, выросли синглтоны. Что интересно — все проблемы остались. Фактически, такой синглтон просто замыкает самые разные контексты и является ни чем иным, как способом управления депенденсами, негибким, проблемным и очень непредсказуемым.
DA>>Т.е. ты за DI и прочие IoC, я правильно понял?

I>Я не знаю, что значит "за DI и IoC".

Okay...
I>Самый интересный вариант IoC на мой взгляд это использование лямбда-выражений в таких вещах, как Linq в .Net или Stream в Джава.
Офигеть, чо.

I>Вероятно, ты имел ввиду управление депенденсами. Да, я за то, что бы управлять депенденсами, при чем явно, что бы все вещи типа состояние, время жизни, аггрегирование, делегирование, композиция и тд были видны с первого взгляда, а не размазывались тонким слоем по сотне классов.

Какие сотни классов?
Тебе не видно состояние в синглтоне?

I>>>Есть простой подход, который позволит понять, о чем идет речь — заменяем слово "синглтон" на "глобальная переменная" и смотрим, что же изменилось. Обычно речь про единственный экземпляр какого то типа. Но, извините, синглтон и единственный экземпляр это немного разные понятия. Синглтон требует, что бы была глобальная точка входа. Более того, должна решаться какая то проблема, например — долгая инициализация, засорение глобального неймспейса и тд.

DA>>При чём тут неймспесы?
I>При том, что глобальные переменные независимо от происхождения засоряют этот самый неймспейс. И часто возникает путаница со всеми сопутствующими проблемами.
Еще раз. При чём глобальный неймспейс к синглтону?

I>>>Множество других применений как правило сильно искусственные. Например класс DataBase. Ну есть у приложения ровно одна база данных, и что с того ? что мешает создавать экземпляры по требованию ? Если технических проблем нет, то синглтонить класс для работы с базой мягко говоря очень странный подход.

DA>>А что, синглтон по требованию созать нельзя?
I>Можно, только зачем ? Ответь на вопрос — какую проблему ты решаешь, делая класс базы данных синглтоном ?
Я не обсуждаю с тобой твои выдуманные примеры БД как синглтона — очевидно, что БД так не делают.
Я у тебя спрашивал именно о выделенном — "что мешает создавать экземпляры по требованию".
Что мешает в случае синглтона?

I>>>1. равно времени жизни экземпляра приложения

I>>>2. больше времени жизни экземпляра приложения
DA>>Какой-то поток сознания...начали с паттерна, перешли к какой-то прикладной проблематике.
I>Именно так и было задумано.
Типичный вариант твоей "дискуссии".
Ikemefula
Ikemefula
23.06.2014 05:30
Здравствуйте, dr. Acula, Вы писали:

DA>Какие сотни классов?


Такие. В больших приложениях много классов.

DA>Тебе не видно состояние в синглтоне?


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

Если создавать инстанс

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

DA>Еще раз. При чём глобальный неймспейс к синглтону?

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

I>>>>Множество других применений как правило сильно искусственные. Например класс DataBase. Ну есть у приложения ровно одна база данных, и что с того ? что мешает создавать экземпляры по требованию ? Если технических проблем нет, то синглтонить класс для работы с базой мягко говоря очень странный подход.

DA>>>А что, синглтон по требованию созать нельзя?
I>>Можно, только зачем ? Ответь на вопрос — какую проблему ты решаешь, делая класс базы данных синглтоном ?
DA>Я не обсуждаю с тобой твои выдуманные примеры БД как синглтона — очевидно, что БД так не делают.

Вообще говоря делают постоянно, не пойму зачем.

DA>Я у тебя спрашивал именно о выделенном — "что мешает создавать экземпляры по требованию".

DA>Что мешает в случае синглтона?

Не понял, ты хочешь иметь синглтон что бы создавать экземпляры по требованию ? А зачем тогда синглтон, если экземпляры создаются по требованию.
Смотри:
var x = new MegaDatabaseClass();


Не пойму, зачем мне здесь какой то синглтон и какую проблему он решит в данном случае

I>>Именно так и было задумано.

DA>Типичный вариант твоей "дискуссии".

Да.
Sinix
Sinix
23.06.2014 07:47
Здравствуйте, Ikemefula, Вы писали:

I>Синоним слова синглтон будет "глобальная переменная". Уже лет 50 все книги-буквари по программированию пишут одно и то же : "Избегайте глобальных переменных". Люди действительно стали избегать — практически везде, где раньше были глобальные переменные, выросли синглтоны. Что интересно — все проблемы остались. Фактически, такой синглтон просто замыкает самые разные контексты и является ни чем иным, как способом управления депенденсами, негибким, проблемным и очень непредсказуемым.


Я бы не ориентировался на рекомендации GoF, они здорово устарели. В более-менее современных источниках пишут буквально то же самое, что и ты:

Nonetheless, singletons have problems similar to globals; e.g., creating dependencies in vastly separated parts of the system, so side effects can appear far afield from their causes. Often singletons are abused by inexperienced programmers who think that the use of the pattern will magically solve all the problems associated with GlobalVariables. (See SingletonGlobalProblems for more.)


Кстати, GoF (насколько помню) нигде не утверждали, что синглтон отличается от глобальной переменной. Скорее, синглтон == глобальной переменной + контроль за отсутствием дублирующих глобальных переменных.
RSATom
RSATom
23.06.2014 08:20
Думаю, когда однажды, количество аргументов некоторой функции перевалит за десяток, синглетон перестанет выглядеть такой уж страшной вещью...
diez_p
diez_p
23.06.2014 11:36
Здравствуйте, RSATom, Вы писали:

RSA>Думаю, когда однажды, количество аргументов некоторой функции перевалит за десяток, синглетон перестанет выглядеть такой уж страшной вещью...


Штоа?! Можно пример проблемы, когда этого не избежать? я вот собственно не понимаю как связано ограничение по количеству объектов недетерминированность время жизни объекта с сигнатурой метода. Это из серии "при какой температуре кипит прямой угол?"
RSATom
RSATom
24.06.2014 03:47
Здравствуйте, diez_p, Вы писали:

_>Здравствуйте, RSATom, Вы писали:


RSA>>Думаю, когда однажды, количество аргументов некоторой функции перевалит за десяток, синглетон перестанет выглядеть такой уж страшной вещью...


_>Штоа?! Можно пример проблемы, когда этого не избежать? я вот собственно не понимаю как связано ограничение по количеству объектов недетерминированность время жизни объекта с сигнатурой метода. Это из серии "при какой температуре кипит прямой угол?"


Ок, приведу пример. В программе могут быть как минимум следующие глобальные (по сути) сущности:
1) Gui Application object — т.е. нечто что необходимо для создания окошек/контролов
2) Logger Object — из названия понятно, для ведения логов.
3) Config Object — для доступа к текущей конфигурации приложения.

Если не использовать синглетоны — огромное количество функций/конструкторов должены будет получать некоторые/все из этих сущностей, а так же передавать далее. Кроме того, в экземлярах классов нужные сущности придется хранить, а это увеличиит каждый экземпляр класса на sizeof(void*) * n, где n = 1..3
__kot2
__kot2
24.06.2014 04:44
Здравствуйте, RSATom, Вы писали:
RSA>Ок, приведу пример. В программе могут быть как минимум следующие глобальные (по сути) сущности:
RSA>1) Gui Application object — т.е. нечто что необходимо для создания окошек/контролов
в нормально спроектированном приложении окошки-контролы создаются не из логики, а только из view, а view по сути и является таким обьектом. но так как мы должны иметь свое view для модели, то нелогично не самом деле иметь view-синглон

RSA>2) Logger Object — из названия понятно, для ведения логов.

да, обычно это синглтон. точнее, это вообще обычно макрос в С++, в явном виде никто с синглтоном не работает

RSA>3) Config Object — для доступа к текущей конфигурации приложения.

"конфиг" это криво реализованная сериализация. не надо на самом деле никаких конфигов городить в нормально спроектированном приложении или по крайней мере это не должно быть синглтоном

RSA>Если не использовать синглетоны — огромное количество функций/конструкторов должены будет получать некоторые/все из этих сущностей, а так же передавать далее. Кроме того, в экземлярах классов нужные сущности придется хранить, а это увеличиит каждый экземпляр класса на sizeof(void*) * n, где n = 1..3

да, это одна из первых проблем новичков. поэтому, как классическое решение, возникают контроллеры сущностей и единая точка доступа к контроллерам приложения, которая да, является синглтоном. но это один синглтон на приложение, а не куча на каждую сущность, существующую в единственном экземпляре
RSATom
RSATom
24.06.2014 05:24
Здравствуйте, __kot2, Вы писали:

__>Здравствуйте, RSATom, Вы писали:

RSA>>Ок, приведу пример. В программе могут быть как минимум следующие глобальные (по сути) сущности:
RSA>>1) Gui Application object — т.е. нечто что необходимо для создания окошек/контролов
__>в нормально спроектированном приложении окошки-контролы создаются не из логики, а только из view, а view по сути и является таким обьектом. но так как мы должны иметь свое view для модели, то нелогично не самом деле иметь view-синглон
view тоже необходимо где то создавать (а при создании нужны некие параметры), если количество view переваливает за некое критическое количество, то их так же приходится группировать, а в эту группу точно так же существует необходимость передачи неких параметров.

RSA>>2) Logger Object — из названия понятно, для ведения логов.

__>да, обычно это синглтон. точнее, это вообще обычно макрос в С++, в явном виде никто с синглтоном не работает
т.е. получается уже как минимум 2 синглетона являются приемлимыми? т.е. тезис о том что синглетон — это "абсолютно зло" уже не работает?

RSA>>3) Config Object — для доступа к текущей конфигурации приложения.

__>"конфиг" это криво реализованная сериализация. не надо на самом деле никаких конфигов городить в нормально спроектированном приложении или по крайней мере это не должно быть синглтоном
Не о сериализации разговор, а о неких параметрах влияющих на логику работы приложения. Частный пример — настройки задаваемые пользователем. Кстати говоря, Сonfig object зачастую тоже может быть не один, т.к. разные части приложения могут быть абсолютно не связаны, и глупо их связывать через общий config


RSA>>Если не использовать синглетоны — огромное количество функций/конструкторов должены будет получать некоторые/все из этих сущностей, а так же передавать далее. Кроме того, в экземлярах классов нужные сущности придется хранить, а это увеличиит каждый экземпляр класса на sizeof(void*) * n, где n = 1..3

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

Опять же, получается что синглетоны имеют право на сущестование? Естествено применять их нужно с умом, но тем не менее?
__kot2
__kot2
24.06.2014 12:45
Здравствуйте, RSATom, Вы писали:
RSA>Опять же, получается что синглетоны имеют право на сущестование? Естествено применять их нужно с умом, но тем не менее?
вообще, я много разного кода насмотрелся и я научился, сам того не хотя, по одному виду определять кем написан код, когда, иногда даже в какой компании или где человек учился

так вот, код с кучей синглтонов, использованных в постах выше характерен для русских студентов 3-4 курса, пишущих без присмотра старшего
больше никто так не делает
RSATom
RSATom
24.06.2014 01:41
Здравствуйте, __kot2, Вы писали:

__>так вот, код с кучей синглтонов, использованных в постах выше характерен для русских студентов 3-4 курса, пишущих без присмотра старшего

__>больше никто так не делает

Заметте, я нигде не говорил про "кучу синглетонов", я говорил лишь о том что не стоит быть столь категоричным...
Суть здесь в том, что практически любую концепцию, практически любого уровня абстракции, теоретически, можно использовать не правильно.
Но это вовсе не значит что эту концепцию нельзя использовать.

Мало того, я сейчас скажу крамольную для многих идею — иногда даже goto полезен...
gravatar
Аноним
24.06.2014 12:58
__>"конфиг" это криво реализованная
Замени-ка "конфиг" на контекст, который может быть вложенным(локальным) — и твоя аргментация улетучивается.

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

Друг, тебе же этот один сингелтон инициализировать надо, так? Вот там и возникнет куча параметров.
Ikemefula
Ikemefula
23.06.2014 12:51
Здравствуйте, RSATom, Вы писали:

RSA>Думаю, когда однажды, количество аргументов некоторой функции перевалит за десяток, синглетон перестанет выглядеть такой уж страшной вещью...


Когда количесттво аргументов увеличивается, нужно свернуть аргументы упаковывая в отдельный класс. Отсюда, внезапно, начинает расти новая абстракция, которую можно рафинировать через рефакторинг при необходимости.
gravatar
Аноним
23.06.2014 08:21
RSA>>когда однажды, количество аргументов некоторой функции перевалит за десяток, синглетон перестанет выглядеть такой уж страшной вещью...
I>Когда количесттво аргументов увеличивается, нужно свернуть аргументы упаковывая в отдельный класс.
Эта мантра не поможет, ибо конструктор(=инициализация) упаковки никуда не денется.
Ikemefula
Ikemefula
23.06.2014 08:41
Здравствуйте, Аноним, Вы писали:

RSA>>>когда однажды, количество аргументов некоторой функции перевалит за десяток, синглетон перестанет выглядеть такой уж страшной вещью...

I>>Когда количесттво аргументов увеличивается, нужно свернуть аргументы упаковывая в отдельный класс.
А>Эта мантра не поможет, ибо конструктор(=инициализация) упаковки никуда не денется.

Это смотря как упаковывать. А после упаковки очень часто нарисовыватся новая абстракция, которую можно полить, окучить и вырастить при желании
gravatar
Аноним
23.06.2014 09:14
I>Это смотря как упаковывать.
А, вы, все еще кипятите? С мантрами всегда так. Главное — чаще повторять. С вами скучно. Гудбай.
AlexRK
AlexRK
24.06.2014 05:55
Здравствуйте, Аноним, Вы писали:

RSA>>>когда однажды, количество аргументов некоторой функции перевалит за десяток, синглетон перестанет выглядеть такой уж страшной вещью...

I>>Когда количесттво аргументов увеличивается, нужно свернуть аргументы упаковывая в отдельный класс.
А>Эта мантра не поможет, ибо конструктор(=инициализация) упаковки никуда не денется.

Речь не о том, чтобы просто упаковать параметры и делать это при каждом вызове. Если функция принимает много параметров, то имеется вероятность, что это вылезает наружу пропущенная абстракция. А раз это полноценная абстракция, то это уже нечто большее, чем тупая структура для передачи данных и вовсе не факт, что мы ее будем создавать при каждом вызове нашей функции.
RSATom
RSATom
24.06.2014 03:50
Здравствуйте, Ikemefula, Вы писали:

I>Здравствуйте, RSATom, Вы писали:


RSA>>Думаю, когда однажды, количество аргументов некоторой функции перевалит за десяток, синглетон перестанет выглядеть такой уж страшной вещью...


I>Когда количесттво аргументов увеличивается, нужно свернуть аргументы упаковывая в отдельный класс. Отсюда, внезапно, начинает расти новая абстракция, которую можно рафинировать через рефакторинг при необходимости.


Можно, но:
а) порой эти аргументы между собой абсолютно не связаны (как например логер и конфиг)
б) разные функции могут требовать разные сочетания параметров — будем плодить структуры на каждое потребовавшееся сочетание? Или создадим суперкласс и свяжем всех со всеми кованными цепями?
AlexRK
AlexRK
24.06.2014 06:01
Здравствуйте, RSATom, Вы писали:

RSA>б) разные функции могут требовать разные сочетания параметров — будем плодить структуры на каждое потребовавшееся сочетание? Или создадим суперкласс и свяжем всех со всеми кованными цепями?


Хм, ну если в приложении имеется много разных функций, каждая из которых имеет большое количество аргументов, которые при этом частично пересекаются между функциями, то у меня для вас плохие новости.
ИМХО, в такой ситуации надо не плодить структуры и не создавать суперклассы, а переделать архитектуру приложения или плюнуть и оставить все, как есть.
Ikemefula
Ikemefula
24.06.2014 06:14
Здравствуйте, AlexRK, Вы писали:

RSA>>б) разные функции могут требовать разные сочетания параметров — будем плодить структуры на каждое потребовавшееся сочетание? Или создадим суперкласс и свяжем всех со всеми кованными цепями?


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

ARK>ИМХО, в такой ситуации надо не плодить структуры и не создавать суперклассы, а переделать архитектуру приложения или плюнуть и оставить все, как есть.

В рефакторинге тухлого кода первые две-три фазы будет просто какая то мелочевка — в основном ради изоляции некоторой части, чтото выделить, чтото заинлайнить, убрать слишком явное дублирование,а кое где наоборот продублировать. В конеце становится известно, в каком направлении надо копать.
То есть, сначала изолируем, режем депенденсы, а потом меняем струкруру.
Ikemefula
Ikemefula
24.06.2014 06:08
Здравствуйте, RSATom, Вы писали:

I>>Когда количесттво аргументов увеличивается, нужно свернуть аргументы упаковывая в отдельный класс. Отсюда, внезапно, начинает расти новая абстракция, которую можно рафинировать через рефакторинг при необходимости.


RSA>Можно, но:

RSA>а) порой эти аргументы между собой абсолютно не связаны (как например логер и конфиг)

Для этого и нужен рефакторинг

RSA>б) разные функции могут требовать разные сочетания параметров — будем плодить структуры на каждое потребовавшееся сочетание? Или создадим суперкласс и свяжем всех со всеми кованными цепями?


Есть решения и для этого. Не пойму чего ты хочешь доказать. Я больше 10 лет занималася вот такими случаями и ничего, удавалось разрулить. Покажи конкретный код, посмотрим.

Вообще большое количество аргументов означает, что функция тащит слишком много обязанностей. Ее будет тяжело майнтейнить, фиксить и тд.
RSATom
RSATom
24.06.2014 08:00
Здравствуйте, Ikemefula, Вы писали:
I>Не пойму чего ты хочешь доказать.

Я хочу доказать что категоричность суждений — удел молодых и горячих...
gravatar
Аноним
24.06.2014 12:46
I>Не пойму чего ты хочешь доказать.
RSA>Я хочу доказать что категоричность суждений — удел молодых и горячих...
Топикстартер не читатель, он писатель. Преклоняюсь перед вашим терпением.
Пример http://www.rsdn.ru/forum/design/5659564.1 — отличный. Хотел тоже самое запостить, но ведь им же не объяснишь, что кошек не любишь они все за свое: "вы просто не умеете их готовить"
Ikemefula
Ikemefula
24.06.2014 01:20
Здравствуйте, RSATom, Вы писали:

I>>Не пойму чего ты хочешь доказать.


RSA>Я хочу доказать что категоричность суждений — удел молодых и горячих...


Я в курсе, спасибо.
__kot2
__kot2
23.06.2014 07:51
Здравствуйте, RSATom, Вы писали:
RSA>Думаю, когда однажды, количество аргументов некоторой функции перевалит за десяток, синглетон перестанет выглядеть такой уж страшной вещью...
единая точка доступа к контроллерам приложения (ее можно назвать App, а я, например, называю Core) это по сути единственный правильный известный мне способ использования синглтона
Nuseraro
Nuseraro
23.06.2014 05:46
I>Синоним слова синглтон будет "глобальная переменная".
Хочу предложить взглянуть на проблему с другой стороны. Рассмотрим случай никак не связанный с синглтонами. У нас есть приложение в котором есть базовый класс по работе с БД. Там уже есть вся инфраструктура по чтению из конфига строки подключения и созданию этого подключения. Тем не менее любой мастер костыля может в наследнике такого класса создать новое подключение и прописать свой метод чтения из конфига. И нет средств языка, которые ему бы помешали это сделать. Получается, средства языка порой очень ограничены в том, чтобы запретить разработчику ошибиться.

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

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

App — это как правило очень сильная связанность, явная или неявная. Получается любой кто хотел знать только про что-нибудь одно, должен/будет знать о всем мире.
RSATom
RSATom
24.06.2014 03:57
Здравствуйте, Nuseraro, Вы писали:

Главная идея вашего сообщения которую мне хотелось бы явно выделить — среди программистов тоже бывают дураки, и термин "защита от дурака", должен применяться не только относительно пользовательских интерфейсов, но и относительно программных. А с учетом возрастающего в геометрической прогрессии количества фреймворков, и среднестатистической уровня знания программистами этих фреймворков — ценность "защиты от дурака" возрастает так же в геометрической прогрессии. Просто потому что разобраться в тонкостях каждого из фреймовроков не хватает времени. А если учесть что фаворит каждые полгода новый...
C.A.B
C.A.B
24.06.2014 11:42
Здравствуйте, Ikemefula, Вы писали:
I>Синоним слова синглтон будет "глобальная переменная"...
Это не так, синглтон это глобальный (в рамках приложения) _объект_. Который кстати говоря может и не содержать переменных.
И, соответственно, используется он когда в предметной области приложения есть глобальная сущность(и).

I>...Например класс DataBase. Ну есть у приложения ровно одна база данных, и что с того ? что мешает создавать экземпляры по требованию ?...

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

I>Есть простой подход, который позволит понять, о чем идет речь — заменяем слово "синглтон" на "глобальная переменная" и смотрим, что же изменилось...

Это как "Заменим слово "бульдозер" на "лопата" и смотрим, что же изменилось"
Ikemefula
Ikemefula
24.06.2014 01:22
Здравствуйте, C.A.B, Вы писали:

CAB>Здравствуйте, Ikemefula, Вы писали:

I>>Синоним слова синглтон будет "глобальная переменная"...
CAB>Это не так, синглтон это глобальный (в рамках приложения) _объект_. Который кстати говоря может и не содержать переменных.
CAB>И, соответственно, используется он когда в предметной области приложения есть глобальная сущность(и).

Вот еще одна концепция синглтонов.

I>>...Например класс DataBase. Ну есть у приложения ровно одна база данных, и что с того ? что мешает создавать экземпляры по требованию ?...

CAB>Например если у приложения есть всего одна база то не логично, не рационально и опасно создать несколько объектов DataBase.

Так расскажи в чем эта опасность и в чем рациональность.

I>>Есть простой подход, который позволит понять, о чем идет речь — заменяем слово "синглтон" на "глобальная переменная" и смотрим, что же изменилось...

CAB>Это как "Заменим слово "бульдозер" на "лопата" и смотрим, что же изменилось"

Скорее "портативный экскаватор с ручным приводом" на "лопата"
C.A.B
C.A.B
24.06.2014 03:26
I>>>...Например класс DataBase. Ну есть у приложения ровно одна база данных, и что с того ? что мешает создавать экземпляры по требованию ?...
CAB>>Например если у приложения есть всего одна база то не логично, не рационально и опасно создать несколько объектов DataBase.
I>Так расскажи в чем эта опасность и в чем рациональность.
Обычные опасности доступа к общему ресурсу , например нарушение последовательности операций, изменение общих параметров и т.п.
Не рационально создавать несколько объектов там где можно обойтись одним. А создавать объекты без состояния вообще бессмысленно.
Ikemefula
Ikemefula
24.06.2014 04:00
Здравствуйте, C.A.B, Вы писали:

I>>>>...Например класс DataBase. Ну есть у приложения ровно одна база данных, и что с того ? что мешает создавать экземпляры по требованию ?...

CAB>>>Например если у приложения есть всего одна база то не логично, не рационально и опасно создать несколько объектов DataBase.
I>>Так расскажи в чем эта опасность и в чем рациональность.
CAB>Обычные опасности доступа к общему ресурсу , например нарушение последовательности операций, изменение общих параметров и т.п.

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

CAB>Не рационально создавать несколько объектов там где можно обойтись одним.


Наоборот. С точки зрения GC создание объектов по необходимости это самый правильный способ. Скажем, Gen0 по скорости сборки уступает только стеку. Не ясно, на чем экономишь. А вот как раз множество долгоживущих объектов создает проблемы, ибо время работы GC прямо зависит от количества старых объектов и связей между ними. Отдельная проблема возникает тогда, когда старый объект держит ссылку на новый.
Проблемы настолько актуальны, что вводится куча оптимизаций. Собственно часть этиъ проблем и решается за счет введения поколений GC.

Есть правда и другой вариант, скажем когда расход памяти велик но очень предсказуем, тогда выделяют всю небходимую память одним куском, что бы исключить GC, и избегают делать вообще какую либо аллокацию через ГЦ. Этот вариант встречается в общей массе настолько редко, что многие его просто не знают.

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

В том же С++ при использовании стековой аллокации снова получаем нулевой расход памяти. И снова не ясно, на чем экономишь.

>А создавать объекты без состояния вообще бессмысленно.


А еще лучше работать с объектами, не зная, какие они, statefull или stateless. С тз операций они могут быть stateless, а унутре statefull. И здесь, вдруг, появляется гибкость — если в сервис придется вставить тротлинг, не мотаться по коду и менять XXXSvc.Run() на this._svc.Run().
C.A.B
C.A.B
24.06.2014 07:38
I>То есть, речь о транзакциях, правильно ?
Если БД то да, но не ими одними.

I>Пудозреваю такое возможно только в тех базах, которые не дают никаких гарантий, не умеют транзакций. Здесь, очевидно, нужно некоторое глобальное состояние.

Не только, допустим у тебя медленный канал и ты желаешь кешировать данные прозрачно для остального приложения, или у тебя не стабильный канал и ты желаешь
скрыть это от остального приложения, или у тебя несколько баз (для надёжности например)... etc.

I> Синглтон это лишь один из способов реализации этого глобального состояния.

Какие другие (в контексте ООП)?


CAB>>Нерационально создавать несколько объектов там где можно обойтись одним.

I>Наоборот. С точки зрения GC создание объектов по необходимости это самый правильный способ.
А с точки зрения процессорного времени?

I>Скажем, Gen0 по скорости сборки уступает только стеку.

Нет лишних объектов -> нет сборки -> нет затрат

I>...А вот как раз множество долгоживущих объектов создает проблемы, ибо время работы GC прямо зависит от количества старых объектов и связей между ними...

Не берусь утверждать, но думаю что объекты созданные при старте программы и живущие всё время её работы, слабо или никак вредят GC, тем более что их
не много.
Ikemefula
Ikemefula
26.06.2014 10:06
Здравствуйте, C.A.B, Вы писали:

I>>Пудозреваю такое возможно только в тех базах, которые не дают никаких гарантий, не умеют транзакций. Здесь, очевидно, нужно некоторое глобальное состояние.

CAB>Не только, допустим у тебя медленный канал и ты желаешь кешировать данные прозрачно для остального приложения, или у тебя не стабильный канал и ты желаешь
CAB>скрыть это от остального приложения, или у тебя несколько баз (для надёжности например)... etc.

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

I>> Синглтон это лишь один из способов реализации этого глобального состояния.

CAB>Какие другие (в контексте ООП)?

Я уже перечислил

CAB>>>Нерационально создавать несколько объектов там где можно обойтись одним.

I>>Наоборот. С точки зрения GC создание объектов по необходимости это самый правильный способ.
CAB>А с точки зрения процессорного времени?

Это именно с точки зрения процессорного времени.

I>>Скажем, Gen0 по скорости сборки уступает только стеку.

CAB>Нет лишних объектов -> нет сборки -> нет затрат

Наоборот, есть объекты, есть сборка и есть затраты. Далеко не любой хип из С++ в раз обставит сборку мусора в Gen0.

I>>...А вот как раз множество долгоживущих объектов создает проблемы, ибо время работы GC прямо зависит от количества старых объектов и связей между ними...

CAB>Не берусь утверждать, но думаю что объекты созданные при старте программы и живущие всё время её работы, слабо или никак вредят GC, тем более что их не много.

Вообще говоря скорость работы GC как минимум линейно зависит от количества долгоживущих объектов. Если объекты ни на что не ссылаются и на них никто не ссылается, то все хорошо. А если глобальный объект держит какой нибудь кеш, а для этого нужны индексы-списки-деревья-хеши, то уже на ровном месте создается нагрузка на GC.
gravatar
Аноним
24.06.2014 01:08
Здравствуйте, Ikemefula, подскажите, какая альтернатива предлагается Logger.log?
Baudolino
Baudolino
24.06.2014 03:18
Здравствуйте, Аноним, Вы писали:

А>Здравствуйте, Ikemefula, подскажите, какая альтернатива предлагается Logger.log?

@Autowired
Logger logger

Ikemefula
Ikemefula
24.06.2014 03:45
Здравствуйте, Аноним, Вы писали:

подскажите, какая альтернатива предлагается Logger.log?

В зависимости от приложении по разному.

Иногда Logger.log, иногда ExecutionContext.Current.Log, иногда this.logger.log(), иногда App.Diag.log()
gravatar
Аноним
24.06.2014 04:43
Здравствуйте, Ikemefula, Вы писали:

I>Здравствуйте, Аноним, Вы писали:


I>подскажите, какая альтернатива предлагается Logger.log?


I>В зависимости от приложении по разному.


I>Иногда Logger.log, иногда ExecutionContext.Current.Log, иногда this.logger.log(), иногда App.Diag.log()


Т.е. Logger будет свойством объекта, а не статическим классом?
Чтобы везде не дублировать его определение, предлагается наследоваться от базового класса с этим свойством?
Ikemefula
Ikemefula
24.06.2014 04:51
Здравствуйте, Аноним, Вы писали:

I>>В зависимости от приложении по разному.


I>>Иногда Logger.log, иногда ExecutionContext.Current.Log, иногда this.logger.log(), иногда App.Diag.log()


А>Т.е. Logger будет свойством объекта, а не статическим классом?

А>Чтобы везде не дублировать его определение, предлагается наследоваться от базового класса с этим свойством?

Я привел целых 4 варианта, неужели непонятно ? Первый вариант статический метод. Второй вариант — некоторой контекст выполнения. Откуда он берется, дело десятое, может в параметре приходит, может свойство, а может и статическое поле — не важно. Третий явно член класса. Четвертый — тот самый синглтон.
gravatar
Аноним
26.06.2014 10:11
I>, может в параметре приходит,
О, коллега осознал, что параметры появляются. Теперь представь, что у тебя их десяток. http://www.rsdn.ru/forum/design/5658239.1
AlexRK
AlexRK
26.06.2014 10:21
Здравствуйте, Аноним, Вы писали:

А>Теперь представь, что у тебя их десяток. http://www.rsdn.ru/forum/design/5658239.1


http://en.wikipedia.org/wiki/Big_ball_of_mud

Вот тут-то нас singleton-driven programming и спасет.
gravatar
Аноним
26.06.2014 10:39
ARK>Вот тут-то нас singleton-driven programming и спасет.
Все зависит от уровня задач. Использование синглтонов оправдано также как и использование внешних функций. Если есть, что сказать по существу, то говори тут: http://www.rsdn.ru/forum/design/5663122.1
Ikemefula
Ikemefula
26.06.2014 10:54
Здравствуйте, Аноним, Вы писали:

А>О, коллега осознал, что параметры появляются. Теперь представь, что у тебя их десяток. http://www.rsdn.ru/forum/design/5658239.1


Скучный аргумент. Есть проблема, когда в методе по 10 параметров, с этим никто не спорит. Скажу страшное — я видел и побольше, и ничего, заборол безо всяких синглтонов.

Было даже так — некотороая операция(конский воркфлоу) принимала 12 параметров, 3 свойства класса, 2 глобальные переменные, Session, плюс, разумеется, Синглтон и до кучи эвент DoRequestParams для запроса недостающих параметров по мере необходимости.

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

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

В итоге выглядело все примерно так:

   using(var x = OperationEx.Create<Concrete1>()) {
          x.Load(args1)
          .Proceed1(args2, x => Predicate1)
          .Proceed2(args3, x => Selector1)
          .Proceed3(args4)
          .Save(args5);

      return x.Result;
   }


args1...5 — это аргументы, по два по три в каждом. После такого изменения, внезапно, стало легко изменять поведение операции, легко параметризировать, вводить новые операции и тд.

Поскольку операция все равно требует много аргументов, то для каждой был выделен класс и вызов операции на самом верху было вот таким


var operation = new Operation
{
   args1 = ...,
   args2 = ...,
   ... 
   args5 = ...,
};

operation.Run();


Фактически, это просто конфиг. Такой код был прямо в контролере. Все аргументы тащились прямо из контекста контролера или параметров метода контролера или через путь от рутового объекта доменной модели.

Это один из вариантов на самом деле. Когда воркфлоу имеет сложную структура, его проще задать не последовательностью операций, а описать конкретной лямбдой. А что бы код не превращался в простыни, нужно подготовить высокоуровневый АПИ, например вместо "показать модальный бокс, проверить результат, если нужный, то продолжить по ём, иначе переключиться на запасной путь" делать вот
так "operation = UserChoice(option1, option2, fallback)"

В итоге параметры никуда особо передавать не надо — лямбда замыкает в свой контекст столько угодно этих параметров без каких либо проблем.
Baudolino
Baudolino
24.06.2014 03:25
Осталось заметить, что синглтоны нарушают SRP, поскольку берут на себя помимо бизнес-роли роль гаранта существования единственного экземпляра.
И добавить, что тестировать код, использующий их, тоже неудобно.
И с сожалением признать, что для инфраструктуры низкого уровня (логгеры и т.п.) выбора нет, т.к. контейнер DI на этом уровне отсутствует (код того же логгера должен быть прост, как сибирский валенок, чтобы суметь записать ошибки старта контейнера DI).
gravatar
Аноним
26.06.2014 10:32
B>И с сожалением признать, что для инфраструктуры низкого уровня (логгеры и т.п.) выбора нет, т.к. контейнер
B>DI на этом уровне отсутствует (код того же логгера должен быть прост, как сибирский валенок, чтобы суметь
B> записать ошибки старта контейнера DI
).
Ничто не мешает использовать для таких случаев бутстрэппинг. Старт(и остановка) контейнера разбивается на нескольк фаз. Сначала создаются временные сервисы(объекты), которые просты "как валенок" и могут работать надежно и автономно. По мере выполнения следующих фаз временные сервисы заменяются на постоянные. Вся проблема в том, что если не использовать синглтоны, то объем контекста растет линейно и его надо как-то передавать. Задача архитектора(дизайнера) лавировать между гибкостью и объемом контекста. Рефакторинг в данном случае это замена шила(отсутствие синглтонов + большой контекст) на мыло(синглтоны + минимальный контекст). Это то, о чем идет речь в ветке http://www.rsdn.ru/forum/design/5658239.1 и то, о чем пока не ведает топикстартер.
AlexRK
AlexRK
26.06.2014 10:47
Здравствуйте, Аноним, Вы писали:

А>замена шила(отсутствие синглтонов + большой контекст) на мыло(синглтоны + минимальный контекст)


Очевидно, что первое гораздо лучше, чем второе — то же самое, что параметры против глобальных переменных. С чего весь топик и начался.
gravatar
Аноним
26.06.2014 11:25
А>>замена шила(отсутствие синглтонов + большой контекст) на мыло(синглтоны + минимальный контекст)
ARK>Очевидно, что первое гораздо лучше
О, носитель абсолютного знания!

Давай я тоже попробую: Очевидно, что делать какие-либо категорические выводы без детального изучения требований, не продуктивно.
AlexRK
AlexRK
26.06.2014 11:37
Здравствуйте, Аноним, Вы писали:

А>О, носитель абсолютного знания!


А без перехода на личности слабО, носитель относительного знания?

А>Давай я тоже попробую: Очевидно, что делать какие-либо категорические выводы без детального изучения требований, не продуктивно.


Fail.
gravatar
Аноним
26.06.2014 12:07
ARK>А без перехода на личности слабО, носитель относительного знания?
Для чего? Количество общего знания от этого не увеличится.

Но тем, не менее, вот отличный пример: http://www.rsdn.ru/forum/design/5659564.1
Если захочешь и сможешь, то разберешся.

P.S: Да, слабо.
AlexRK
AlexRK
26.06.2014 12:30
Здравствуйте, Аноним, Вы писали:

А>Для чего? Количество общего знания от этого не увеличится.


Намекаете, что ценность ваших слов около нуля? Ну зачем же так.

А>Но тем, не менее, вот отличный пример: http://www.rsdn.ru/forum/design/5659564.1

А>Если захочешь и сможешь, то разберешся.

На этот отличный пример уже были даны ответы. Если с логгером еще можно согласиться, то остальное весьма сомнительно. На крайний случай можно ввести один корневой синглтон с логгером и еще парой атрибутов.
Baudolino
Baudolino
26.06.2014 03:50
А>>замена шила(отсутствие синглтонов + большой контекст) на мыло(синглтоны + минимальный контекст)
ARK>Очевидно, что первое гораздо лучше, чем второе — то же самое, что параметры против глобальных переменных. С чего весь топик и начался.
Не очевидно.
gravatar
Аноним Слава синглтонам!
26.06.2014 01:17
Глобальным переменным слава!

// Видишь синглтон?
// Do work using connection
void boo()
{
            using (var connection = CreateConnection())
            {                
              bla. bla. bla.
              ...
              bla.
            }
}
//  — Нет!

// — И я не вижу. А он есть!
void foo()
{
        using (var scope = CreateScope())
        {
            // Do transactional work
            boo();
            scope.Complete();
        }
}
Ikemefula
Ikemefula
27.06.2014 06:52
Здравствуйте, Аноним, Вы писали:

А>Глобальным переменным слава!


А>
А>// Видишь синглтон?
...
А>// — И я не вижу. А он есть!
А>


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

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