О синглтонах
22.06.2014
|
Pauel |
Синоним слова синглтон будет "глобальная переменная". Уже лет 50 все книги-буквари по программированию пишут одно и то же : "Избегайте глобальных переменных". Люди действительно стали избегать — практически везде, где раньше были глобальные переменные, выросли синглтоны. Что интересно — все проблемы остались. Фактически, такой синглтон просто замыкает самые разные контексты и является ни чем иным, как способом управления депенденсами, негибким, проблемным и очень непредсказуемым.
Есть простой подход, который позволит понять, о чем идет речь — заменяем слово "синглтон" на "глобальная переменная" и смотрим, что же изменилось. Обычно речь про единственный экземпляр какого то типа. Но, извините, синглтон и единственный экземпляр это немного разные понятия. Синглтон требует, что бы была глобальная точка входа. Более того, должна решаться какая то проблема, например — долгая инициализация, засорение глобального неймспейса и тд.
Вобщем, получается так, что для паттерна Синглтон есть почти одно применение — глобальный объект навроде App.
Множество других применений как правило сильно искусственные. Например класс DataBase. Ну есть у приложения ровно одна база данных, и что с того ? что мешает создавать экземпляры по требованию ? Если технических проблем нет, то синглтонить класс для работы с базой мягко говоря очень странный подход.
Вообще говоря, мой подход с паттернам примерно такой — сначала решить задачу, а потом переводить решение в код. Если на втором этапе возникают ассоциации с паттернами, то, как вариант, можно посмотреть варианты решения просто для уточнения деталей. Писать или не писать конкретный паттерн явно в коде это вообще дело десятое. Паттерн вообще должен решать одну или несколько реальных проблем и, при этом, должен хорошо вписываться в глобальный дизайн решения. Если этого нет, то паттерн есть просто баззворд.
За употребление паттернов на первом этапе, то есть на стадии поиска и принятия решения, считаю, надо бить по рукам, головам, почкам и даже ниже пояса любыми способами — явными, неявными, прямыми, косвенными, симметричными, ассиметричными и тд и тд и тд.
Если ограничить применение Синглтона именно глобальным объектом App, то, внезапно, из этого можно извлечь целый ряд профитов. Например можно ввести просто адскую диагностику средствами REPL. А можно менять стратегии персистанса глобального состояния. Забрать у классов эту обязанность и переложить её на фремворк приложения — пусть он решает, где и как будет сохраняться состояние приложения и будет ли вообще сохраняться. Что же должно храниться в этом объекте ? Хранить нужно собтсвенно состояние, время жизни которого
1. равно времени жизни экземпляра приложения
2. больше времени жизни экземпляра приложения
Собственно всё.
Есть простой подход, который позволит понять, о чем идет речь — заменяем слово "синглтон" на "глобальная переменная" и смотрим, что же изменилось. Обычно речь про единственный экземпляр какого то типа. Но, извините, синглтон и единственный экземпляр это немного разные понятия. Синглтон требует, что бы была глобальная точка входа. Более того, должна решаться какая то проблема, например — долгая инициализация, засорение глобального неймспейса и тд.
Вобщем, получается так, что для паттерна Синглтон есть почти одно применение — глобальный объект навроде App.
Множество других применений как правило сильно искусственные. Например класс DataBase. Ну есть у приложения ровно одна база данных, и что с того ? что мешает создавать экземпляры по требованию ? Если технических проблем нет, то синглтонить класс для работы с базой мягко говоря очень странный подход.
Вообще говоря, мой подход с паттернам примерно такой — сначала решить задачу, а потом переводить решение в код. Если на втором этапе возникают ассоциации с паттернами, то, как вариант, можно посмотреть варианты решения просто для уточнения деталей. Писать или не писать конкретный паттерн явно в коде это вообще дело десятое. Паттерн вообще должен решать одну или несколько реальных проблем и, при этом, должен хорошо вписываться в глобальный дизайн решения. Если этого нет, то паттерн есть просто баззворд.
За употребление паттернов на первом этапе, то есть на стадии поиска и принятия решения, считаю, надо бить по рукам, головам, почкам и даже ниже пояса любыми способами — явными, неявными, прямыми, косвенными, симметричными, ассиметричными и тд и тд и тд.
Если ограничить применение Синглтона именно глобальным объектом App, то, внезапно, из этого можно извлечь целый ряд профитов. Например можно ввести просто адскую диагностику средствами REPL. А можно менять стратегии персистанса глобального состояния. Забрать у классов эту обязанность и переложить её на фремворк приложения — пусть он решает, где и как будет сохраняться состояние приложения и будет ли вообще сохраняться. Что же должно храниться в этом объекте ? Хранить нужно собтсвенно состояние, время жизни которого
1. равно времени жизни экземпляра приложения
2. больше времени жизни экземпляра приложения
Собственно всё.
23.06.14 13:05: Перенесено модератором из 'Блоги' — AndrewVK
22.06.2014 57 комментариев |
Т.е. ты за DI и прочие IoC, я правильно понял?
I>Есть простой подход, который позволит понять, о чем идет речь — заменяем слово "синглтон" на "глобальная переменная" и смотрим, что же изменилось. Обычно речь про единственный экземпляр какого то типа. Но, извините, синглтон и единственный экземпляр это немного разные понятия. Синглтон требует, что бы была глобальная точка входа. Более того, должна решаться какая то проблема, например — долгая инициализация, засорение глобального неймспейса и тд.
При чём тут неймспесы?
I>Вобщем, получается так, что для паттерна Синглтон есть почти одно применение — глобальный объект навроде App.
У кого получается? У тебя?
Это прекрасно.
I>Множество других применений как правило сильно искусственные. Например класс DataBase. Ну есть у приложения ровно одна база данных, и что с того ? что мешает создавать экземпляры по требованию ? Если технических проблем нет, то синглтонить класс для работы с базой мягко говоря очень странный подход.
А что, синглтон по требованию созать нельзя?
I>Вообще говоря, мой подход с паттернам примерно такой — сначала решить задачу, а потом переводить решение в код. Если на втором этапе возникают ассоциации с паттернами, то, как вариант, можно посмотреть варианты решения просто для уточнения деталей. Писать или не писать конкретный паттерн явно в коде это вообще дело десятое.
I>За употребление паттернов на первом этапе, то есть на стадии поиска и принятия решения, считаю, надо бить по рукам, головам, почкам и даже ниже пояса любыми способами — явными, неявными, прямыми, косвенными, симметричными, ассиметричными и тд и тд и тд.
Да-да, и тут ты на Белом Коне с шакой наголо.
I>Если ограничить применение Синглтона именно глобальным объектом App, то, внезапно, из этого можно извлечь целый ряд профитов. Например можно ввести просто адскую диагностику средствами REPL. А можно менять стратегии персистанса глобального состояния. Забрать у классов эту обязанность и переложить её на фремворк приложения — пусть он решает, где и как будет сохраняться состояние приложения и будет ли вообще сохраняться. Что же должно храниться в этом объекте ? Хранить нужно собтсвенно состояние, время жизни которого
I>1. равно времени жизни экземпляра приложения
I>2. больше времени жизни экземпляра приложения
Какой-то поток сознания...начали с паттерна, перешли к какой-то прикладной проблематике.
I>Собственно всё.
Ниачём.
Ждём срыва покровов с goto.
I>>Синоним слова синглтон будет "глобальная переменная". Уже лет 50 все книги-буквари по программированию пишут одно и то же : "Избегайте глобальных переменных". Люди действительно стали избегать — практически везде, где раньше были глобальные переменные, выросли синглтоны. Что интересно — все проблемы остались. Фактически, такой синглтон просто замыкает самые разные контексты и является ни чем иным, как способом управления депенденсами, негибким, проблемным и очень непредсказуемым.
DA>Т.е. ты за DI и прочие IoC, я правильно понял?
Я не знаю, что значит "за DI и IoC". Самый интересный вариант IoC на мой взгляд это использование лямбда-выражений в таких вещах, как Linq в .Net или Stream в Джава.
Вероятно, ты имел ввиду управление депенденсами. Да, я за то, что бы управлять депенденсами, при чем явно, что бы все вещи типа состояние, время жизни, аггрегирование, делегирование, композиция и тд были видны с первого взгляда, а не размазывались тонким слоем по сотне классов.
I>>Есть простой подход, который позволит понять, о чем идет речь — заменяем слово "синглтон" на "глобальная переменная" и смотрим, что же изменилось. Обычно речь про единственный экземпляр какого то типа. Но, извините, синглтон и единственный экземпляр это немного разные понятия. Синглтон требует, что бы была глобальная точка входа. Более того, должна решаться какая то проблема, например — долгая инициализация, засорение глобального неймспейса и тд.
DA>При чём тут неймспесы?
При том, что глобальные переменные независимо от происхождения засоряют этот самый неймспейс. И часто возникает путаница со всеми сопутствующими проблемами.
I>>Множество других применений как правило сильно искусственные. Например класс DataBase. Ну есть у приложения ровно одна база данных, и что с того ? что мешает создавать экземпляры по требованию ? Если технических проблем нет, то синглтонить класс для работы с базой мягко говоря очень странный подход.
DA>А что, синглтон по требованию созать нельзя?
Можно, только зачем ? Ответь на вопрос — какую проблему ты решаешь, делая класс базы данных синглтоном ?
I>>1. равно времени жизни экземпляра приложения
I>>2. больше времени жизни экземпляра приложения
DA>Какой-то поток сознания...начали с паттерна, перешли к какой-то прикладной проблематике.
Именно так и было задумано.
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>Именно так и было задумано.
Типичный вариант твоей "дискуссии".
DA>Какие сотни классов?
Такие. В больших приложениях много классов.
DA>Тебе не видно состояние в синглтоне?
Нет, не видно. Синглтон всегда имеет состояние и это состояние пинают все, кому не лень. Отсюда ясно, что в каждом конкретном месте ты видишь только малую часть, а остальная нигде не видна.
Если создавать инстанс
I>>При том, что глобальные переменные независимо от происхождения засоряют этот самый неймспейс. И часто возникает путаница со всеми сопутствующими проблемами.
DA>Еще раз. При чём глобальный неймспейс к синглтону?
А ты понимаешь, что я говорю о том, что синглтоны пришли на замену глобальным переменным ? Ты понимаешь, что глобальные переменные означали кучу глобально видимых функций.
I>>>>Множество других применений как правило сильно искусственные. Например класс DataBase. Ну есть у приложения ровно одна база данных, и что с того ? что мешает создавать экземпляры по требованию ? Если технических проблем нет, то синглтонить класс для работы с базой мягко говоря очень странный подход.
DA>>>А что, синглтон по требованию созать нельзя?
I>>Можно, только зачем ? Ответь на вопрос — какую проблему ты решаешь, делая класс базы данных синглтоном ?
DA>Я не обсуждаю с тобой твои выдуманные примеры БД как синглтона — очевидно, что БД так не делают.
Вообще говоря делают постоянно, не пойму зачем.
DA>Я у тебя спрашивал именно о выделенном — "что мешает создавать экземпляры по требованию".
DA>Что мешает в случае синглтона?
Не понял, ты хочешь иметь синглтон что бы создавать экземпляры по требованию ? А зачем тогда синглтон, если экземпляры создаются по требованию.
Смотри:
Не пойму, зачем мне здесь какой то синглтон и какую проблему он решит в данном случае
I>>Именно так и было задумано.
DA>Типичный вариант твоей "дискуссии".
Да.
I>Синоним слова синглтон будет "глобальная переменная". Уже лет 50 все книги-буквари по программированию пишут одно и то же : "Избегайте глобальных переменных". Люди действительно стали избегать — практически везде, где раньше были глобальные переменные, выросли синглтоны. Что интересно — все проблемы остались. Фактически, такой синглтон просто замыкает самые разные контексты и является ни чем иным, как способом управления депенденсами, негибким, проблемным и очень непредсказуемым.
Я бы не ориентировался на рекомендации GoF, они здорово устарели. В более-менее современных источниках пишут буквально то же самое, что и ты:
Кстати, GoF (насколько помню) нигде не утверждали, что синглтон отличается от глобальной переменной. Скорее, синглтон == глобальной переменной + контроль за отсутствием дублирующих глобальных переменных.
RSA>Думаю, когда однажды, количество аргументов некоторой функции перевалит за десяток, синглетон перестанет выглядеть такой уж страшной вещью...
Штоа?! Можно пример проблемы, когда этого не избежать? я вот собственно не понимаю как связано ограничение по количеству объектов недетерминированность время жизни объекта с сигнатурой метода. Это из серии "при какой температуре кипит прямой угол?"
_>Здравствуйте, RSATom, Вы писали:
RSA>>Думаю, когда однажды, количество аргументов некоторой функции перевалит за десяток, синглетон перестанет выглядеть такой уж страшной вещью...
_>Штоа?! Можно пример проблемы, когда этого не избежать? я вот собственно не понимаю как связано ограничение по количеству объектов недетерминированность время жизни объекта с сигнатурой метода. Это из серии "при какой температуре кипит прямой угол?"
Ок, приведу пример. В программе могут быть как минимум следующие глобальные (по сути) сущности:
1) Gui Application object — т.е. нечто что необходимо для создания окошек/контролов
2) Logger Object — из названия понятно, для ведения логов.
3) Config Object — для доступа к текущей конфигурации приложения.
Если не использовать синглетоны — огромное количество функций/конструкторов должены будет получать некоторые/все из этих сущностей, а так же передавать далее. Кроме того, в экземлярах классов нужные сущности придется хранить, а это увеличиит каждый экземпляр класса на sizeof(void*) * n, где n = 1..3
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, Вы писали:
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
__>да, это одна из первых проблем новичков. поэтому, как классическое решение, возникают контроллеры сущностей и единая точка доступа к контроллерам приложения, которая да, является синглтоном. но это один синглтон на приложение, а не куча на каждую сущность, существующую в единственном экземпляре
Опять же, получается что синглетоны имеют право на сущестование? Естествено применять их нужно с умом, но тем не менее?
RSA>Опять же, получается что синглетоны имеют право на сущестование? Естествено применять их нужно с умом, но тем не менее?
вообще, я много разного кода насмотрелся и я научился, сам того не хотя, по одному виду определять кем написан код, когда, иногда даже в какой компании или где человек учился
так вот, код с кучей синглтонов, использованных в постах выше характерен для русских студентов 3-4 курса, пишущих без присмотра старшего
больше никто так не делает
__>так вот, код с кучей синглтонов, использованных в постах выше характерен для русских студентов 3-4 курса, пишущих без присмотра старшего
__>больше никто так не делает
Заметте, я нигде не говорил про "кучу синглетонов", я говорил лишь о том что не стоит быть столь категоричным...
Суть здесь в том, что практически любую концепцию, практически любого уровня абстракции, теоретически, можно использовать не правильно.
Но это вовсе не значит что эту концепцию нельзя использовать.
Мало того, я сейчас скажу крамольную для многих идею — иногда даже goto полезен...
Замени-ка "конфиг" на контекст, который может быть вложенным(локальным) — и твоя аргментация улетучивается.
__>поэтому, как классическое решение, возникают контроллеры сущностей и единая точка доступа к контроллерам приложения, которая да, является синглтоном. но это один синглтон на приложение, а не куча на каждую сущность, существующую в единственном экземпляре
Друг, тебе же этот один сингелтон инициализировать надо, так? Вот там и возникнет куча параметров.
RSA>Думаю, когда однажды, количество аргументов некоторой функции перевалит за десяток, синглетон перестанет выглядеть такой уж страшной вещью...
Когда количесттво аргументов увеличивается, нужно свернуть аргументы упаковывая в отдельный класс. Отсюда, внезапно, начинает расти новая абстракция, которую можно рафинировать через рефакторинг при необходимости.
I>Когда количесттво аргументов увеличивается, нужно свернуть аргументы упаковывая в отдельный класс.
Эта мантра не поможет, ибо конструктор(=инициализация) упаковки никуда не денется.
RSA>>>когда однажды, количество аргументов некоторой функции перевалит за десяток, синглетон перестанет выглядеть такой уж страшной вещью...
I>>Когда количесттво аргументов увеличивается, нужно свернуть аргументы упаковывая в отдельный класс.
А>Эта мантра не поможет, ибо конструктор(=инициализация) упаковки никуда не денется.
Это смотря как упаковывать. А после упаковки очень часто нарисовыватся новая абстракция, которую можно полить, окучить и вырастить при желании
А, вы, все еще кипятите? С мантрами всегда так. Главное — чаще повторять. С вами скучно. Гудбай.
RSA>>>когда однажды, количество аргументов некоторой функции перевалит за десяток, синглетон перестанет выглядеть такой уж страшной вещью...
I>>Когда количесттво аргументов увеличивается, нужно свернуть аргументы упаковывая в отдельный класс.
А>Эта мантра не поможет, ибо конструктор(=инициализация) упаковки никуда не денется.
Речь не о том, чтобы просто упаковать параметры и делать это при каждом вызове. Если функция принимает много параметров, то имеется вероятность, что это вылезает наружу пропущенная абстракция. А раз это полноценная абстракция, то это уже нечто большее, чем тупая структура для передачи данных и вовсе не факт, что мы ее будем создавать при каждом вызове нашей функции.
I>Здравствуйте, RSATom, Вы писали:
RSA>>Думаю, когда однажды, количество аргументов некоторой функции перевалит за десяток, синглетон перестанет выглядеть такой уж страшной вещью...
I>Когда количесттво аргументов увеличивается, нужно свернуть аргументы упаковывая в отдельный класс. Отсюда, внезапно, начинает расти новая абстракция, которую можно рафинировать через рефакторинг при необходимости.
Можно, но:
а) порой эти аргументы между собой абсолютно не связаны (как например логер и конфиг)
б) разные функции могут требовать разные сочетания параметров — будем плодить структуры на каждое потребовавшееся сочетание? Или создадим суперкласс и свяжем всех со всеми кованными цепями?
RSA>б) разные функции могут требовать разные сочетания параметров — будем плодить структуры на каждое потребовавшееся сочетание? Или создадим суперкласс и свяжем всех со всеми кованными цепями?
Хм, ну если в приложении имеется много разных функций, каждая из которых имеет большое количество аргументов, которые при этом частично пересекаются между функциями, то у меня для вас плохие новости.
ИМХО, в такой ситуации надо не плодить структуры и не создавать суперклассы, а переделать архитектуру приложения или плюнуть и оставить все, как есть.
RSA>>б) разные функции могут требовать разные сочетания параметров — будем плодить структуры на каждое потребовавшееся сочетание? Или создадим суперкласс и свяжем всех со всеми кованными цепями?
ARK>Хм, ну если в приложении имеется много разных функций, каждая из которых имеет большое количество аргументов, которые при этом частично пересекаются между функциями, то у меня для вас плохие новости.
ARK>ИМХО, в такой ситуации надо не плодить структуры и не создавать суперклассы, а переделать архитектуру приложения или плюнуть и оставить все, как есть.
В рефакторинге тухлого кода первые две-три фазы будет просто какая то мелочевка — в основном ради изоляции некоторой части, чтото выделить, чтото заинлайнить, убрать слишком явное дублирование,а кое где наоборот продублировать. В конеце становится известно, в каком направлении надо копать.
То есть, сначала изолируем, режем депенденсы, а потом меняем струкруру.
I>>Когда количесттво аргументов увеличивается, нужно свернуть аргументы упаковывая в отдельный класс. Отсюда, внезапно, начинает расти новая абстракция, которую можно рафинировать через рефакторинг при необходимости.
RSA>Можно, но:
RSA>а) порой эти аргументы между собой абсолютно не связаны (как например логер и конфиг)
Для этого и нужен рефакторинг
RSA>б) разные функции могут требовать разные сочетания параметров — будем плодить структуры на каждое потребовавшееся сочетание? Или создадим суперкласс и свяжем всех со всеми кованными цепями?
Есть решения и для этого. Не пойму чего ты хочешь доказать. Я больше 10 лет занималася вот такими случаями и ничего, удавалось разрулить. Покажи конкретный код, посмотрим.
Вообще большое количество аргументов означает, что функция тащит слишком много обязанностей. Ее будет тяжело майнтейнить, фиксить и тд.
I>Не пойму чего ты хочешь доказать.
Я хочу доказать что категоричность суждений — удел молодых и горячих...
RSA>Я хочу доказать что категоричность суждений — удел молодых и горячих...
Топикстартер не читатель, он писатель. Преклоняюсь перед вашим терпением.
Пример http://www.rsdn.ru/forum/design/5659564.1 — отличный. Хотел тоже самое запостить, но ведь им же не объяснишь, что кошек не любишь они все за свое: "вы просто не умеете их готовить"
I>>Не пойму чего ты хочешь доказать.
RSA>Я хочу доказать что категоричность суждений — удел молодых и горячих...
Я в курсе, спасибо.
RSA>Думаю, когда однажды, количество аргументов некоторой функции перевалит за десяток, синглетон перестанет выглядеть такой уж страшной вещью...
единая точка доступа к контроллерам приложения (ее можно назвать App, а я, например, называю Core) это по сути единственный правильный известный мне способ использования синглтона
Хочу предложить взглянуть на проблему с другой стороны. Рассмотрим случай никак не связанный с синглтонами. У нас есть приложение в котором есть базовый класс по работе с БД. Там уже есть вся инфраструктура по чтению из конфига строки подключения и созданию этого подключения. Тем не менее любой мастер костыля может в наследнике такого класса создать новое подключение и прописать свой метод чтения из конфига. И нет средств языка, которые ему бы помешали это сделать. Получается, средства языка порой очень ограничены в том, чтобы запретить разработчику ошибиться.
Вообще, все прайвты, паблики, зоны видимости и прочее — это же про "защиту от дурака", намек на то, как надо использовать код. Но ищущий костыля всегда найдет способ хакнуть прайвт метод через рефлекшн.
Вернемся к синглтону. На мой взгляд, тот факт что синглтон == глобальная переменная — это просто случайное совпадение в реально существующих языках. Цель паттерна синглтон простая — обеспечить, чтобы всегда был единственный экземпляр класса. То, что при этом этот единственный экземпляр можно вызвать напрямую отовсюду — это печально, но не более печально, чем то, что для обычного класса можно всюду создать новый экземпляр, как в примере выше. Ну а как правильно использовать синглтон — не секрет, надо обозначать его использование, передавая его в конструктор или свойства класса явно.
App — это как правило очень сильная связанность, явная или неявная. Получается любой кто хотел знать только про что-нибудь одно, должен/будет знать о всем мире.
Главная идея вашего сообщения которую мне хотелось бы явно выделить — среди программистов тоже бывают дураки, и термин "защита от дурака", должен применяться не только относительно пользовательских интерфейсов, но и относительно программных. А с учетом возрастающего в геометрической прогрессии количества фреймворков, и среднестатистической уровня знания программистами этих фреймворков — ценность "защиты от дурака" возрастает так же в геометрической прогрессии. Просто потому что разобраться в тонкостях каждого из фреймовроков не хватает времени. А если учесть что фаворит каждые полгода новый...
I>Синоним слова синглтон будет "глобальная переменная"...
Это не так, синглтон это глобальный (в рамках приложения) _объект_. Который кстати говоря может и не содержать переменных.
И, соответственно, используется он когда в предметной области приложения есть глобальная сущность(и).
I>...Например класс DataBase. Ну есть у приложения ровно одна база данных, и что с того ? что мешает создавать экземпляры по требованию ?...
Например если у приложения есть всего одна база то не логично, не рационально и опасно создать несколько объектов DataBase.
I>Есть простой подход, который позволит понять, о чем идет речь — заменяем слово "синглтон" на "глобальная переменная" и смотрим, что же изменилось...
Это как "Заменим слово "бульдозер" на "лопата" и смотрим, что же изменилось"
CAB>Здравствуйте, Ikemefula, Вы писали:
I>>Синоним слова синглтон будет "глобальная переменная"...
CAB>Это не так, синглтон это глобальный (в рамках приложения) _объект_. Который кстати говоря может и не содержать переменных.
CAB>И, соответственно, используется он когда в предметной области приложения есть глобальная сущность(и).
Вот еще одна концепция синглтонов.
I>>...Например класс DataBase. Ну есть у приложения ровно одна база данных, и что с того ? что мешает создавать экземпляры по требованию ?...
CAB>Например если у приложения есть всего одна база то не логично, не рационально и опасно создать несколько объектов DataBase.
Так расскажи в чем эта опасность и в чем рациональность.
I>>Есть простой подход, который позволит понять, о чем идет речь — заменяем слово "синглтон" на "глобальная переменная" и смотрим, что же изменилось...
CAB>Это как "Заменим слово "бульдозер" на "лопата" и смотрим, что же изменилось"
Скорее "портативный экскаватор с ручным приводом" на "лопата"
CAB>>Например если у приложения есть всего одна база то не логично, не рационально и опасно создать несколько объектов DataBase.
I>Так расскажи в чем эта опасность и в чем рациональность.
Обычные опасности доступа к общему ресурсу , например нарушение последовательности операций, изменение общих параметров и т.п.
Не рационально создавать несколько объектов там где можно обойтись одним. А создавать объекты без состояния вообще бессмысленно.
I>>>>...Например класс DataBase. Ну есть у приложения ровно одна база данных, и что с того ? что мешает создавать экземпляры по требованию ?...
CAB>>>Например если у приложения есть всего одна база то не логично, не рационально и опасно создать несколько объектов DataBase.
I>>Так расскажи в чем эта опасность и в чем рациональность.
CAB>Обычные опасности доступа к общему ресурсу , например нарушение последовательности операций, изменение общих параметров и т.п.
То есть, речь о транзакциях, правильно ? Пудозреваю такое возможно только в тех базах, которые не дают никаких гарантий, не умеют транзакций. Здесь, очевидно, нужно некоторое глобальное состояние. Синглтон это лишь один из способов реализации этого глобального состояния.
CAB>Не рационально создавать несколько объектов там где можно обойтись одним.
Наоборот. С точки зрения GC создание объектов по необходимости это самый правильный способ. Скажем, Gen0 по скорости сборки уступает только стеку. Не ясно, на чем экономишь. А вот как раз множество долгоживущих объектов создает проблемы, ибо время работы GC прямо зависит от количества старых объектов и связей между ними. Отдельная проблема возникает тогда, когда старый объект держит ссылку на новый.
Проблемы настолько актуальны, что вводится куча оптимизаций. Собственно часть этиъ проблем и решается за счет введения поколений GC.
Есть правда и другой вариант, скажем когда расход памяти велик но очень предсказуем, тогда выделяют всю небходимую память одним куском, что бы исключить GC, и избегают делать вообще какую либо аллокацию через ГЦ. Этот вариант встречается в общей массе настолько редко, что многие его просто не знают.
Ну и есть варианты, когда приходится выжимать каждый такт и бит. С ними большй частью ответ один — не та платформа, а востальных случаях можно из статические методы дергать.
В том же С++ при использовании стековой аллокации снова получаем нулевой расход памяти. И снова не ясно, на чем экономишь.
>А создавать объекты без состояния вообще бессмысленно.
А еще лучше работать с объектами, не зная, какие они, statefull или stateless. С тз операций они могут быть stateless, а унутре statefull. И здесь, вдруг, появляется гибкость — если в сервис придется вставить тротлинг, не мотаться по коду и менять XXXSvc.Run() на this._svc.Run().
Если БД то да, но не ими одними.
I>Пудозреваю такое возможно только в тех базах, которые не дают никаких гарантий, не умеют транзакций. Здесь, очевидно, нужно некоторое глобальное состояние.
Не только, допустим у тебя медленный канал и ты желаешь кешировать данные прозрачно для остального приложения, или у тебя не стабильный канал и ты желаешь
скрыть это от остального приложения, или у тебя несколько баз (для надёжности например)... etc.
I> Синглтон это лишь один из способов реализации этого глобального состояния.
Какие другие (в контексте ООП)?
CAB>>Нерационально создавать несколько объектов там где можно обойтись одним.
I>Наоборот. С точки зрения GC создание объектов по необходимости это самый правильный способ.
А с точки зрения процессорного времени?
I>Скажем, Gen0 по скорости сборки уступает только стеку.
Нет лишних объектов -> нет сборки -> нет затрат
I>...А вот как раз множество долгоживущих объектов создает проблемы, ибо время работы GC прямо зависит от количества старых объектов и связей между ними...
Не берусь утверждать, но думаю что объекты созданные при старте программы и живущие всё время её работы, слабо или никак вредят GC, тем более что их
не много.
I>>Пудозреваю такое возможно только в тех базах, которые не дают никаких гарантий, не умеют транзакций. Здесь, очевидно, нужно некоторое глобальное состояние.
CAB>Не только, допустим у тебя медленный канал и ты желаешь кешировать данные прозрачно для остального приложения, или у тебя не стабильный канал и ты желаешь
CAB>скрыть это от остального приложения, или у тебя несколько баз (для надёжности например)... etc.
Здесь можно обойтись одной точкой входа на весь фремворк БД или на приложение. Здесь нет ничего военного, при правильном дизайне в отсутствие кеша будет только провал в перформансе. А вот с транзакциями будет просто фейл.
I>> Синглтон это лишь один из способов реализации этого глобального состояния.
CAB>Какие другие (в контексте ООП)?
Я уже перечислил
CAB>>>Нерационально создавать несколько объектов там где можно обойтись одним.
I>>Наоборот. С точки зрения GC создание объектов по необходимости это самый правильный способ.
CAB>А с точки зрения процессорного времени?
Это именно с точки зрения процессорного времени.
I>>Скажем, Gen0 по скорости сборки уступает только стеку.
CAB>Нет лишних объектов -> нет сборки -> нет затрат
Наоборот, есть объекты, есть сборка и есть затраты. Далеко не любой хип из С++ в раз обставит сборку мусора в Gen0.
I>>...А вот как раз множество долгоживущих объектов создает проблемы, ибо время работы GC прямо зависит от количества старых объектов и связей между ними...
CAB>Не берусь утверждать, но думаю что объекты созданные при старте программы и живущие всё время её работы, слабо или никак вредят GC, тем более что их не много.
Вообще говоря скорость работы GC как минимум линейно зависит от количества долгоживущих объектов. Если объекты ни на что не ссылаются и на них никто не ссылается, то все хорошо. А если глобальный объект держит какой нибудь кеш, а для этого нужны индексы-списки-деревья-хеши, то уже на ровном месте создается нагрузка на GC.
А>Здравствуйте, Ikemefula, подскажите, какая альтернатива предлагается Logger.log?
@Autowired
Logger logger
подскажите, какая альтернатива предлагается Logger.log?
В зависимости от приложении по разному.
Иногда Logger.log, иногда ExecutionContext.Current.Log, иногда this.logger.log(), иногда App.Diag.log()
I>Здравствуйте, Аноним, Вы писали:
I>подскажите, какая альтернатива предлагается Logger.log?
I>В зависимости от приложении по разному.
I>Иногда Logger.log, иногда ExecutionContext.Current.Log, иногда this.logger.log(), иногда App.Diag.log()
Т.е. Logger будет свойством объекта, а не статическим классом?
Чтобы везде не дублировать его определение, предлагается наследоваться от базового класса с этим свойством?
I>>В зависимости от приложении по разному.
I>>Иногда Logger.log, иногда ExecutionContext.Current.Log, иногда this.logger.log(), иногда App.Diag.log()
А>Т.е. Logger будет свойством объекта, а не статическим классом?
А>Чтобы везде не дублировать его определение, предлагается наследоваться от базового класса с этим свойством?
Я привел целых 4 варианта, неужели непонятно ? Первый вариант статический метод. Второй вариант — некоторой контекст выполнения. Откуда он берется, дело десятое, может в параметре приходит, может свойство, а может и статическое поле — не важно. Третий явно член класса. Четвертый — тот самый синглтон.
О, коллега осознал, что параметры появляются. Теперь представь, что у тебя их десяток. http://www.rsdn.ru/forum/design/5658239.1
А>Теперь представь, что у тебя их десяток. http://www.rsdn.ru/forum/design/5658239.1
http://en.wikipedia.org/wiki/Big_ball_of_mud
Вот тут-то нас singleton-driven programming и спасет.
Все зависит от уровня задач. Использование синглтонов оправдано также как и использование внешних функций. Если есть, что сказать по существу, то говори тут: http://www.rsdn.ru/forum/design/5663122.1
А>О, коллега осознал, что параметры появляются. Теперь представь, что у тебя их десяток. http://www.rsdn.ru/forum/design/5658239.1
Скучный аргумент. Есть проблема, когда в методе по 10 параметров, с этим никто не спорит. Скажу страшное — я видел и побольше, и ничего, заборол безо всяких синглтонов.
Было даже так — некотороая операция(конский воркфлоу) принимала 12 параметров, 3 свойства класса, 2 глобальные переменные, Session, плюс, разумеется, Синглтон и до кучи эвент DoRequestParams для запроса недостающих параметров по мере необходимости.
Все это я разрулил примерно за одну неделю, устранив синглтон, Session, глобальные переменные и дурацкий эвент. В результате появился один базовый класс, у него три или четыре наследника, один статический класс без состояния.
Большую часть времени я просто разбирался, для чего и как используются аргументы, и из каких частей состоит вся операция, и на какие части её можно поделить
В итоге выглядело все примерно так:
args1...5 — это аргументы, по два по три в каждом. После такого изменения, внезапно, стало легко изменять поведение операции, легко параметризировать, вводить новые операции и тд.
Поскольку операция все равно требует много аргументов, то для каждой был выделен класс и вызов операции на самом верху было вот таким
Фактически, это просто конфиг. Такой код был прямо в контролере. Все аргументы тащились прямо из контекста контролера или параметров метода контролера или через путь от рутового объекта доменной модели.
Это один из вариантов на самом деле. Когда воркфлоу имеет сложную структура, его проще задать не последовательностью операций, а описать конкретной лямбдой. А что бы код не превращался в простыни, нужно подготовить высокоуровневый АПИ, например вместо "показать модальный бокс, проверить результат, если нужный, то продолжить по ём, иначе переключиться на запасной путь" делать вот
так "operation = UserChoice(option1, option2, fallback)"
В итоге параметры никуда особо передавать не надо — лямбда замыкает в свой контекст столько угодно этих параметров без каких либо проблем.
И добавить, что тестировать код, использующий их, тоже неудобно.
И с сожалением признать, что для инфраструктуры низкого уровня (логгеры и т.п.) выбора нет, т.к. контейнер DI на этом уровне отсутствует (код того же логгера должен быть прост, как сибирский валенок, чтобы суметь записать ошибки старта контейнера DI).
B>DI на этом уровне отсутствует (код того же логгера должен быть прост, как сибирский валенок, чтобы суметь
B> записать ошибки старта контейнера DI).
Ничто не мешает использовать для таких случаев бутстрэппинг. Старт(и остановка) контейнера разбивается на нескольк фаз. Сначала создаются временные сервисы(объекты), которые просты "как валенок" и могут работать надежно и автономно. По мере выполнения следующих фаз временные сервисы заменяются на постоянные. Вся проблема в том, что если не использовать синглтоны, то объем контекста растет линейно и его надо как-то передавать. Задача архитектора(дизайнера) лавировать между гибкостью и объемом контекста. Рефакторинг в данном случае это замена шила(отсутствие синглтонов + большой контекст) на мыло(синглтоны + минимальный контекст). Это то, о чем идет речь в ветке http://www.rsdn.ru/forum/design/5658239.1 и то, о чем пока не ведает топикстартер.
А>замена шила(отсутствие синглтонов + большой контекст) на мыло(синглтоны + минимальный контекст)
Очевидно, что первое гораздо лучше, чем второе — то же самое, что параметры против глобальных переменных. С чего весь топик и начался.
ARK>Очевидно, что первое гораздо лучше
О, носитель абсолютного знания!
Давай я тоже попробую: Очевидно, что делать какие-либо категорические выводы без детального изучения требований, не продуктивно.
А>О, носитель абсолютного знания!
А без перехода на личности слабО, носитель относительного знания?
А>Давай я тоже попробую: Очевидно, что делать какие-либо категорические выводы без детального изучения требований, не продуктивно.
Fail.
Для чего? Количество общего знания от этого не увеличится.
Но тем, не менее, вот отличный пример: http://www.rsdn.ru/forum/design/5659564.1
Если захочешь и сможешь, то разберешся.
P.S: Да, слабо.
А>Для чего? Количество общего знания от этого не увеличится.
Намекаете, что ценность ваших слов около нуля? Ну зачем же так.
А>Но тем, не менее, вот отличный пример: http://www.rsdn.ru/forum/design/5659564.1
А>Если захочешь и сможешь, то разберешся.
На этот отличный пример уже были даны ответы. Если с логгером еще можно согласиться, то остальное весьма сомнительно. На крайний случай можно ввести один корневой синглтон с логгером и еще парой атрибутов.
ARK>Очевидно, что первое гораздо лучше, чем второе — то же самое, что параметры против глобальных переменных. С чего весь топик и начался.
Не очевидно.
А>Глобальным переменным слава!
А>
Это красота ради красоты. Для решения реальных проблем нужно четко знать, какие депенденсы каким образом используются. То есть, депенденсы должны распространяться явно, а не распихиваться по уголочкам.
Собтсвенно связи, а в частности это депенденсы, и есть та самая хрень, которая обеспечивает 99% сложности решения.
От количества сущностей сложность растет линейно. От количества связей хорошо если экспоненциально, потому что даже факториальная сложность достигается элементарно.