Здравствуйте!
Есть несколько вопросов по поводу subj'а.
1) В чем преимущество этого паттерна перед классом со статическими методами?
2) Приведите хотя бы пару примеров где РЕАЛЬНО помогает реализация данного паттерна?
3) Почему у некоторых программистов такое отрицательное отношение к глобальным/статическим переменным/классам/методам и паттерну singleton?
Спасибо.
Re: По поводу паттерна singleton и не только
От:
Аноним
Дата:
18.09.07 09:09
Оценка:
Здравствуйте, Kazna4ey, Вы писали:
K>3) Почему у некоторых программистов такое отрицательное отношение к глобальным/статическим переменным/классам/методам и паттерну singleton?
Глобальные переменные плохи тем, что доступ к ним слабо контролируем. Синглтон-класс — немногим лучше.
Для себя вывел правило: синглтон может безопасно существовать в системе, но использующие его модули НЕ должны знать, что это синглтон. Т.е. модуль должен при инициализации получать экземпляр класса MyClass как провайдера требуемого функционала (dependency injection или типа того), но НЕ дложен звать всякие статик-методы типа MyClass::getInstance() или getMyClassSingleton().
Ибо условия задачи могут (и будут) поменяться, и вместо использования синглтона может потребоваться доступ к нескольким разным экземплярам класса MyClass, где бывший синглтон-экземпляр — всего лишь дефолтный вариант. И вычищать логику, опиравшуюся на статик-методы, ой как неприятно и муторно потом.
Здравствуйте, Kazna4ey, Вы писали:
K>1) В чем преимущество этого паттерна перед классом со статическими методами?
Позволяет использовать контролируемое число экземпляров (а не только один). Можно передать, можно унаследоваться.
K>3) Почему у некоторых программистов такое отрицательное отношение к глобальным/статическим переменным/классам/методам и паттерну singleton? http://rsdn3.rsdn.ru/forum/message/2615563.1.aspx
>Глобальные переменные плохи тем, что доступ к ним слабо контролируем.
Т.е.? Можно подробнее?
>K>3) Почему у некоторых программистов такое отрицательное отношение к глобальным/статическим переменным/классам/методам и паттерну singleton? http://rsdn3.rsdn.ru/forum/message/2615563.1.aspx
Прочитал, уши повяли. Простите — разные уровни. Можете, кратко объяснить в расчете на программиста с 2х летним опытом?
Ради интереса начал думать где в своих проектах я мог бы реализовать singleton, чтобы попробовать и сравнить с тем как было без него. Нашел несколько мест.
Например есть MDI-приложение, и кое-какая форма должна открываться только в единственном экземпляре, при этом не запрещая параллельную работу с остальными формами.
Скажите, такая реализация singleton — нормальная?
public class UpdaterForm : System.Windows.Forms.Form
{
private static UpdaterForm pInstance;
...
public static UpdaterForm GetInstance()
{
if (pInstance == null || pInstance.IsDisposed)
pInstance = new UpdaterForm();
else
{
// Форма "мигает" чтобы пользователь видел что она уже открыта
pInstance.WindowState = FormWindowState.Minimized;
pInstance.WindowState = FormWindowState.Normal;
}
return pInstance;
}
private UpdaterForm()
{
InitializeComponent();
}
...
}
Ну и вызываю конечно так:
UpdaterForm p = UpdaterForm.GetInstance();
p.MdiParent = MDIParent;
p.Show();
Здравствуйте, Kazna4ey, Вы писали:
K>Ради интереса начал думать где в своих проектах я мог бы реализовать singleton, чтобы попробовать и сравнить с тем как было без него. Нашел несколько мест. K>Например есть MDI-приложение, и кое-какая форма должна открываться только в единственном экземпляре, при этом не запрещая параллельную работу с остальными формами. K>Скажите, такая реализация singleton — нормальная?
Не а
Я как то пока совсем не вижу необходимости в реализации синглетона. Но так как задачи не знаю — оставлю за скобками.
K>
K>public class UpdaterForm : System.Windows.Forms.Form
K>{
K> private static UpdaterForm pInstance;
K> ...
K> public static UpdaterForm GetInstance()
K> {
K> if (pInstance == null || pInstance.IsDisposed)
K> pInstance = new UpdaterForm();
K> else
K> {
//Ты определись - либо тут реализация синглетона, либо мигалка. Черевато боком.
K> // Форма "мигает" чтобы пользователь видел что она уже открыта
K> pInstance.WindowState = FormWindowState.Minimized;
K> pInstance.WindowState = FormWindowState.Normal;
K> }
K> return pInstance;
K> }
K> private UpdaterForm()
K> {
K> InitializeComponent();
K> }
K> ...
K>}
K>
K>Ну и вызываю конечно так: K>
K> UpdaterForm p = UpdaterForm.GetInstance();
//а вот это совсем жесть :(
K> p.MdiParent = MDIParent;
K> p.Show();
//Потом напишем someVar = p; то есть сохраним ссылку на синглетон
//И позовем его откуда то еще (тот же код), наверно ничего хорошего не выйдет если попользоваться someVar?
K>
Здравствуйте, Kazna4ey, Вы писали:
K>Ради интереса начал думать где в своих проектах я мог бы реализовать singleton, чтобы попробовать и сравнить с тем как было без него. Нашел несколько мест. K>Например есть MDI-приложение, и кое-какая форма должна открываться только в единственном экземпляре, при этом не запрещая параллельную работу с остальными формами. K>Скажите, такая реализация singleton — нормальная?
Нет, не нормальная. Не дело это, когда форма сама решает одна она будет или несколько. Пусть решает тот, кто ее создает. Раз он зачем-то ее создает, значит он и знает сколько и зачем ему эти формы нужны.
Здравствуйте, MaximVK, Вы писали:
MVK>Нет, не нормальная. Не дело это, когда форма сама решает одна она будет или несколько. Пусть решает тот, кто ее создает. Раз он зачем-то ее создает, значит он и знает сколько и зачем ему эти формы нужны.
Особенно забавно будет смотреть, как эту не по годам умную формочку будут делить два экземпляра программы, запущенные в рамках одной виртуальной машины.
K>>3) Почему у некоторых программистов такое отрицательное отношение к глобальным/статическим переменным/классам/методам и паттерну singleton?
А>Глобальные переменные плохи тем, что доступ к ним слабо контролируем. Синглтон-класс — немногим лучше. А>Для себя вывел правило: синглтон может безопасно существовать в системе, но использующие его модули НЕ должны знать, что это синглтон. Т.е. модуль должен при инициализации получать экземпляр класса MyClass как провайдера требуемого функционала (dependency injection или типа того), но НЕ дложен звать всякие статик-методы типа MyClass::getInstance() или getMyClassSingleton().
Там, где этого легко добиться, то так и надо делать. Но если синглетон должен быть использован где-то глубоко внутри реализации, то, выигрывая в расширяемости, мы проигрываем в сложности кода, так как нам надо будет тянуть все необходимые синглетоны через все иерархии классов, или прийдется создавать что-то типа сервиса именования и все-равно для каждого объекта тянуть глобальный контекст. А это не всегда возможно — есть унаследованный и сторонний код. В общем, избавляясь от одних сложностей, мы получаем другие, не меньшие.
Для себя я использую два правила:
1. Оформлять в синглетон можно только логические подсистемы приложения (что-то типа фасадов, за которыми скрыта обособленная функциональность).
2. Синглетон отвечает только за доступ к функциональности; инициализация и деинициализация соответствующих объектов все-равно должна выполняться явно.
А>Ибо условия задачи могут (и будут) поменяться, и вместо использования синглтона может потребоваться доступ к нескольким разным экземплярам класса MyClass, где бывший синглтон-экземпляр — всего лишь дефолтный вариант. И вычищать логику, опиравшуюся на статик-методы, ой как неприятно и муторно потом.
Ну это вопрос архитектуры. Такое может произойти, но надо всегда взвешивать шансы. Там где это более вероятно, то синглетон конечно использовать не стоит.
K>Ради интереса начал думать где в своих проектах я мог бы реализовать singleton, чтобы попробовать и сравнить с тем как было без него. Нашел несколько мест. K>Например есть MDI-приложение, и кое-какая форма должна открываться только в единственном экземпляре, при этом не запрещая параллельную работу с остальными формами. K>Скажите, такая реализация singleton — нормальная?
Нет, я бы сделал так — контроллер, который создает формы (например, в ответ на команды), очевидно должен иметь список созданных и активных форм, а каждый класс (фабрика) формы должен иметь признак — допускается ли одновременное существование нескольких форм данного вида; если нет, то перед созданием формы в списке ищется форма того же класса, она же и используется. Синглетон тут совершенно излишен.
Здравствуйте, Kazna4ey, Вы писали:
K> Есть несколько вопросов по поводу subj'а.
K>1) В чем преимущество этого паттерна перед классом со статическими методами?
В том, что не надо делать new.
K>2) Приведите хотя бы пару примеров где РЕАЛЬНО помогает реализация данного паттерна?
Там, где гарантированно должен существовать только один экземпляр класса. Примеры: много принтеров, но только один спуллер,
различные IoC контейнеры, логгеры и т.д.
K>3) Почему у некоторых программистов такое отрицательное отношение к глобальным/статическим переменным/классам/методам и паттерну singleton?
Потому, что они не знают как и где его применять.
K>>Скажите, такая реализация singleton — нормальная? GIV>Не а GIV>Я как то пока совсем не вижу необходимости в реализации синглетона. Но так как задачи не знаю — оставлю за скобками.
Задача:
Форма может вызываться из разных мест в программе. Однако нужно чтобы она была всегда одна, т.е. не вызывалось 2 формы.
GIV>//Ты определись — либо тут реализация синглетона, либо мигалка. Черевато боком.
Чем мигание мешает реализации синглтона? Если кроме самого понятия синглтона класс не будет ничего делать, зачем тогда такой синглтон?
K>>Ну и вызываю конечно так: K>>[c#] K>> UpdaterForm p = UpdaterForm.GetInstance(); GIV>//а вот это совсем жесть K>> p.MdiParent = MDIParent; K>> p.Show(); GIV>//Потом напишем someVar = p; то есть сохраним ссылку на синглетон GIV>//И позовем его откуда то еще (тот же код), наверно ничего хорошего не выйдет если попользоваться someVar?
Не понимаю в чем проблема? Если этот код вызовем в другом месте — ничего плохого не произойдет, форма мигнет, давая понять что она уже открыта.
K>>Скажите, такая реализация singleton — нормальная?
MVK>Нет, не нормальная. Не дело это, когда форма сама решает одна она будет или несколько. Пусть решает тот, кто ее создает. Раз он зачем-то ее создает, значит он и знает сколько и зачем ему эти формы нужны.
Если так рассуждать, то паттерн синглтон получился бы совсем не нужным, программист бы сам всегда решал "сколько и зачем". А тут как раз уже все решено — форма должна быть только одна — и в этом решении помогает реализация синглтона. Что не так?
R>Особенно забавно будет смотреть, как эту не по годам умную формочку будут делить два экземпляра программы, запущенные в рамках одной виртуальной машины.
COF>Нет, я бы сделал так — контроллер, который создает формы (например, в ответ на команды), очевидно должен иметь список созданных и активных форм, а каждый класс (фабрика) формы должен иметь признак — допускается ли одновременное существование нескольких форм данного вида; если нет, то перед созданием формы в списке ищется форма того же класса, она же и используется. Синглетон тут совершенно излишен.
Такой вариант абсолютно возможен. Только чем излишен синглтон, если его реализация добавляет 5 строк кода и решает задачу?
Здравствуйте, Kazna4ey, Вы писали:
K>Объясните пожалуйста.
Представьте простую программу: таймер — по запуску отображаются часы с секундной стрелкой и запускается отсчет времени. Чтобы отсчитывать секунды форма подписывается на события некоторого таймера-счетчика, который периодически шлет ей событие с указанием отсчитанного времени: по этому событию форма перерисует текущее положение секундной стрелки. И пусть форма будет, как в приведенном выше коде, Singleton-ом. Допустим, пользователь открыл таймер, отсчитал 30 секунд а потом, случайно так, снова нажал дважды-быстро на ярлыке программы. В итоге мы получим (в этом примере, конечно, запустятся разные экземпляры виртуальных машин, но это уже тонкости): форма — 1 шт., таймер-счетчик — 2 шт. — причем каждый со своим видением на то, сколько секунд уже натикало. В итоге, вторая форма не откроется, зато в уже открытой секундная стрелка будет скакать как бешеная туда-сюда. Вот такое групповое изнасилование формочки.
Здравствуйте, Kazna4ey, Вы писали:
K>>>Скажите, такая реализация singleton — нормальная? GIV>>Не а GIV>>Я как то пока совсем не вижу необходимости в реализации синглетона. Но так как задачи не знаю — оставлю за скобками.
K>Задача: K>Форма может вызываться из разных мест в программе. Однако нужно чтобы она была всегда одна, т.е. не вызывалось 2 формы.
Нет, это не задача. Пример того что можно назвать задачей: Есть прога в которой можно открыть много документов (MDI), для текущего (активного) документа должна отображаться история изменений (кем, когда). Окно для отображения истории документа должно буть в единственном экземпляре.
В такой постановке я не стал бы делать форму синглетоном. А сделал бы следующее:
— контроллер отслуживает активацию\деакивацию представления "Документ"
— контроллер по этим событиям обновляет ссылку на документ в представлении "История изменений" из ставшего активным представления "Документ"
Соотвественно контроллер содержит ссылки на все представления "Документ" и на представление "История изменений".
Он же занимается отправкой команд на мигание\показать\спрятать и всего прочего.
Как видишь обошлись без синглетонов...
GIV>>//Ты определись — либо тут реализация синглетона, либо мигалка. Черевато боком.
K>Чем мигание мешает реализации синглтона? Если кроме самого понятия синглтона класс не будет ничего делать, зачем тогда такой синглтон?
Нельзя получить ссылку на инстанс синглетона без побочных эффектов (мигания)
K>>>Ну и вызываю конечно так: K>>>[c#] K>>> UpdaterForm p = UpdaterForm.GetInstance(); GIV>>//а вот это совсем жесть K>>> p.MdiParent = MDIParent; K>>> p.Show(); GIV>>//Потом напишем someVar = p; то есть сохраним ссылку на синглетон GIV>>//И позовем его откуда то еще (тот же код), наверно ничего хорошего не выйдет если попользоваться someVar?
K>Не понимаю в чем проблема? Если этот код вызовем в другом месте — ничего плохого не произойдет, форма мигнет, давая понять что она уже открыта.
Проблема в MDIParent и в Show() — синглетон с состоянием — это жесть. В обном месте ему устанавливают одно состояние в другом другое, о чем в первом месте конечно никто не догадывается и считает что все ок.
Здравствуйте, Kazna4ey, Вы писали:
COF>>Нет, я бы сделал так — контроллер, который создает формы (например, в ответ на команды), очевидно должен иметь список созданных и активных форм, а каждый класс (фабрика) формы должен иметь признак — допускается ли одновременное существование нескольких форм данного вида; если нет, то перед созданием формы в списке ищется форма того же класса, она же и используется. Синглетон тут совершенно излишен.
K>Такой вариант абсолютно возможен. Только чем излишен синглтон, если его реализация добавляет 5 строк кода и решает задачу?
На самом деле, можно и синглетон. Просто это решает несколько другую задачу — или в системе должна существовать одна форма, или в контроллере. Часто это одно и то же, но может быть и нет — тут уже приводили пример. На самом деле, я допускаю, что может существовать задача, когда форма вообще может быть одна на все инстанции приложения. Но в этом случае контроллер, получив эту форму от фабрики, обязательно должен проверить, кому принадлежит эта форма — никому, ему или другому контроллеру и действовать соответственно, например вывести сообщение о том, что форма не может быть показана, так как она уже открыта где-то еще. Самое интересное, что реализация с синглетоном оказывается ничуть не проще, чем без него.
Здравствуйте, Kazna4ey, Вы писали:
MVK>>Пусть решает тот, кто ее создает. Раз он зачем-то ее создает, значит он и знает сколько и зачем ему эти формы нужны.
K>Если так рассуждать, то паттерн синглтон получился бы совсем не нужным, программист бы сам всегда решал "сколько и зачем".
Совершенно верно — он не нужен здесь.
"For every complex problem, there is a solution that is simple, neat,
and wrong."
Здравствуйте, kuj, Вы писали:
K>>1) В чем преимущество этого паттерна перед классом со статическими методами? kuj>В том, что не надо делать new.
И в чём же преемущество? Да, и перед чем преимущество?
K>>2) Приведите хотя бы пару примеров где РЕАЛЬНО помогает реализация данного паттерна? kuj>Там, где гарантированно должен существовать только один экземпляр класса. Примеры: много принтеров, но только один спуллер, kuj>различные IoC контейнеры, логгеры и т.д.
Сделать "IoC-контейнер" синглетоном…
K>>3) Почему у некоторых программистов такое отрицательное отношение к глобальным/статическим переменным/классам/методам и паттерну singleton? kuj>Потому, что они не знают как и где его применять.
Это те "не знают как и где его применять", кто "ещё", а те же, кто "уже", не применяют потому что "знают"
... << RSDN@Home 1.2.0 alpha rev. 717>>
Help will always be given at Hogwarts to those who ask for it.
Здравствуйте, _FRED_, Вы писали:
K>>>1) В чем преимущество этого паттерна перед классом со статическими методами? kuj>>В том, что не надо делать new.
_FR>И в чём же преемущество?
В отсутствии overhead`а и в простой логичности подхода. Читая код, легко распознается singleton, сложно — monostate-class. _FR>Да, и перед чем преимущество?
Ваш вопрос ^.
K>>>2) Приведите хотя бы пару примеров где РЕАЛЬНО помогает реализация данного паттерна? kuj>>Там, где гарантированно должен существовать только один экземпляр класса. Примеры: много принтеров, но только один спуллер, kuj>>различные IoC контейнеры, логгеры и т.д.
_FR>Сделать "IoC-контейнер" синглетоном…
В некоторых случаях IoC-контейнер должен быть синглтоном. Не во всех, далеко не во всех, ясное дело.
K>>>3) Почему у некоторых программистов такое отрицательное отношение к глобальным/статическим переменным/классам/методам и паттерну singleton? kuj>>Потому, что они не знают как и где его применять.
_FR>Это те "не знают как и где его применять", кто "ещё", а те же, кто "уже", не применяют потому что "знают"
Не применяете потому, что не знаете как применять.
Добавлю еще: для singleton`а в отличии от monostate-класса можно делать subclassing
В singleton "встроенна" защита от т.н. "infinite circular initialization", когда у вас два разных monostate-класса обращаются к статическим свойствам друг друга. Редкая ситуация — согласен, ошибка в проектировании — согласен, но ведь языки программирования для того и нужны, чтоб защищать нас — людей от врожденного порока — допускать ошибки.
P.S. Если желаете продолжать данный спор просьба отвечать по существу, либо не отвечать совсем. Ответы в стиле: синглтон — зло точка оставьте пожалуйста при себе.