Комментарии 31
SRP забыли.
Приватный конструктор + френд на класс An забыли.
Приватный конструктор + френд на класс An забыли.
0
Френд на класс будет описан в последующих статьях по мере развития класса. Не совсем понятно, зачем нужен приватный конструктор?
0
SRP не упомянул, хотя можно было бы. На мой взгляд, данный факт является более теоретическим и является довольно спорным. Но, как несложно догадаться, приведенный подход решает также и эту проблему.
0
«Паттерн» уже, конечно, в русскоязычной литературе определение устоявшееся, к сожалению, но «синглтон»… Лучше уж тогда родное название использовать.
-1
Очень подробно про синглтон и его подводные камни для .Net: csharpindepth.com/Articles/General/Singleton.aspx
0
Про многопоточность хорошо бы упомянуть сразу — ваш синглтон (иногда по книжке называемый синглтон Майерса) в таком виде не «threadsafe»…
0
Будет про многопоточность, но позже. Невозможно охватить все аспекты в одной статье, т.к. хочется подробно описать такой важный вопрос. Я планирую продолжение этого топика с освещением вопросов про время жизни, многопоточность и различные плюшки.
+1
Когда мы получаем доступ к экземпляру класса, мы не знаем текущее состояние этого класса, и кто и когда его менял, и это состояние может быть вовсе не таким, как ожидается. Иными словами, корректность работы с синглтоном зависит от порядка обращений к нему, что вызывает неявную зависимость подсистем друг от друга и, как следствие, серьезно усложняет разработку.
Когда мы получаем доступ к базе данных, мы не знаем текущее состояние этой базы, и кто и когда его менял, и это состояние может быть вовсе не таким, как ожидается. Иными словами, корректность работы с базой данных зависит от порядка обращений к ней, что вызывает неявную зависимость подсистем друг от друга и, как следствие, серьезно усложняет разработку.
Нет?
А за статью спасибо, интересно.
Когда мы получаем доступ к базе данных, мы не знаем текущее состояние этой базы, и кто и когда его менял, и это состояние может быть вовсе не таким, как ожидается. Иными словами, корректность работы с базой данных зависит от порядка обращений к ней, что вызывает неявную зависимость подсистем друг от друга и, как следствие, серьезно усложняет разработку.
Нет?
А за статью спасибо, интересно.
+1
В целом да, но в базе данных есть один трюк. И хотя мы не знаем состояния, мы открываем транзакцию и на некоторое время фиксируем состояние грубо говоря. Потом начинаем выяснять это состояние (SELECT), и затем — изменять (INSERT,UPDATE,DELETE). Т.е. процесс происходит так, как будто мы ничего не знаем о текущем состоянии. При этом транзакция гарантирует, что никто не вмешается и не испортим нам получение состояния. Поэтому такая транзакционность упрощает взаимодействие с базой данных.
В целом, не стоит воспринимать данный тезис как то, что происходит всегда без исключений. Но об этом все же стоит помнить при проектировании/использовании.
В целом, не стоит воспринимать данный тезис как то, что происходит всегда без исключений. Но об этом все же стоит помнить при проектировании/использовании.
0
>>И хотя мы не знаем состояния, мы открываем транзакцию и на некоторое время фиксируем состояние грубо говоря. Потом начинаем выяснять это состояние (SELECT), и затем — изменять (INSERT,UPDATE,DELETE).
Вы описали какой-то предельный случай. В жизни все несколько проще, никто не делает SELECT перед каждым INSERT.
Дам контрпример.
У меня есть объект логгера. Он один на приложение и даже на группу приложений. Знать его состояние для меня — избыточно, оно меня не волнует совершенно. Если что-то случится — он выбросит исключение.
А вот иметь такой объект ровно один (поскольку для лога должен быть только один вход) — жизненно необходимо.
Резюме — понятие «состояние» имеет косвенное отношение к паттерну «одиночка».
Вы описали какой-то предельный случай. В жизни все несколько проще, никто не делает SELECT перед каждым INSERT.
Дам контрпример.
У меня есть объект логгера. Он один на приложение и даже на группу приложений. Знать его состояние для меня — избыточно, оно меня не волнует совершенно. Если что-то случится — он выбросит исключение.
А вот иметь такой объект ровно один (поскольку для лога должен быть только один вход) — жизненно необходимо.
Резюме — понятие «состояние» имеет косвенное отношение к паттерну «одиночка».
0
Для логгера есть состояние, например — открытый файл. Если файл закрыт, то в лог писать нет смысла. К тому же файл могут удалить и логи перестанут записываться, если не сделать дополнительные приседания. В данном случае вызывающему объекту не нужно знать о состоянии, синглтон его должен поддерживать самостоятельно. Но об этом важно помнить.
0
Для логгера есть состояние, например — открытый файл. Если файл закрыт, то в лог писать нет смысла.
А зачем мне об этом вообще знать?
Надо будет — логгер бросит исключение. Не бросил — отлично, значит продолжаем.
Инкапсуляция же? Зачем свое состояние объект вообще должен кому-либо показывать? Есть интерфейсы, вот ими и пользуйтесь.
А зачем мне об этом вообще знать?
Надо будет — логгер бросит исключение. Не бросил — отлично, значит продолжаем.
Инкапсуляция же? Зачем свое состояние объект вообще должен кому-либо показывать? Есть интерфейсы, вот ими и пользуйтесь.
0
Зачем там куча шаблонных классов, которые только запутывают понимание всего происходящего?
В чем преимущество Вашего решения пред следующим кодом?
Про шаблонный Singleton очень хорошо написано в книге Адександреску — Современное проектирование на c++
И кстати есть готовое решение — библиотека Loki
В чем преимущество Вашего решения пред следующим кодом?
//Singleton.h
class Singleton
{
private:
Singleton();
//disallow copy and assign
Singleton(const Singleton&);
Singleton& operator=(const Singleton&);
public:
Singleton& GetInstance();
};
.....
//Singleton.cpp
Singleton& Singleton::GetInstance()
{
static Singleton g_Instance;
return g_Instance;
}
Singleton::Singleton()
{
}
Про шаблонный Singleton очень хорошо написано в книге Адександреску — Современное проектирование на c++
И кстати есть готовое решение — библиотека Loki
0
Ответ заключается в том, что такой подход содержит в себе все недостатки, перечисленные в начале статьи. Как следствие, при кажущейся простоте, появляется трудность при расширении и превращении синглтона не в синглтон. Например, мы знаем, что у нас есть один экран и поэтому логично использовать синглтон для отрисовки изображения. Но потом появляется второй экран и выясняется, что все надо переделывать. Предложенный подход не настаивает на использовании синглтона, и в следующих статьях я покажу, как можно это использовать.
0
Если предполагается заменять Singleton на не Singleton, то это явно ошибка в проектировании, и паттерн Singleton здесь ни при чем. Singleton это изначально один глобальный объект, он создается как один, и не предполагает наличия нескольких копий, это суть паттерна, которую нельзя нарушать!
Если появляется необходимость рефакторинга, который предпогалает наличие нескольких копий объекта, который раньше был Singleon, то нужно отказываться от паттерна Singleton и заменять его на что-нибудь другое, может быть что-то типа фабрики объектов.
Я видел в реальном проекте использование нескольких копий объекта Singleon, это было просто ужасно!
Если появляется необходимость рефакторинга, который предпогалает наличие нескольких копий объекта, который раньше был Singleon, то нужно отказываться от паттерна Singleton и заменять его на что-нибудь другое, может быть что-то типа фабрики объектов.
Я видел в реальном проекте использование нескольких копий объекта Singleon, это было просто ужасно!
0
как то у вас не согласуется факт чтения Александреску и приведенный код)
плюшка предложенного топикстартером решения — универсальность, мы один раз пишем реализацию синглтона и сотни раз ее используем с разными классами, в вашем же случае придется для каждого класса писать реализацию отдельно, это как минимум
плюшка предложенного топикстартером решения — универсальность, мы один раз пишем реализацию синглтона и сотни раз ее используем с разными классами, в вашем же случае придется для каждого класса писать реализацию отдельно, это как минимум
0
По Вашему мнению человек, прочитавший Александреску должен тут-же накладывать тонны запутанного кода только лишь ради универсальности?
Универсальность — это удел библиотек, таких как буст и stl, к коим код данной стати, как говорится, и в подметки не годится.
Тот-же Александреску в другой своей книге пишет что «Главное — корректность, простота и ясность»
Стандарты проектирования на C++. 101 правило и рекомендации.
Книгу я привел в пример потому, что в ней рассматривается паттерн Singleton настолько детально, что мало ли что еще можно туда добавить.
Также решение, сделанное в библиотеке Loki (про которую и рассказывается в книге) довольно универсальное и сделанное на основе стратегий — можно настраивать детали реализации при помощи параметров шаблона, а не принимать компромиссные решения, навязываемые библиотекой, чего нет в данной статье.
Универсальность — это удел библиотек, таких как буст и stl, к коим код данной стати, как говорится, и в подметки не годится.
Тот-же Александреску в другой своей книге пишет что «Главное — корректность, простота и ясность»
Стандарты проектирования на C++. 101 правило и рекомендации.
Книгу я привел в пример потому, что в ней рассматривается паттерн Singleton настолько детально, что мало ли что еще можно туда добавить.
Также решение, сделанное в библиотеке Loki (про которую и рассказывается в книге) довольно универсальное и сделанное на основе стратегий — можно настраивать детали реализации при помощи параметров шаблона, а не принимать компромиссные решения, навязываемые библиотекой, чего нет в данной статье.
0
Боюсь, вы не поняли основной посыл статьи. Речь в ней идет не о реализации, а об использовании. Собственно, это даже написано в заголовке. При этом реализацию можно взять из предложенного вами куска кода. Можно взять реализацию из Александреску. Книжка его очень умная и толковая. Но вся статья написана о том, как использовать и убрать недостатки, присущие этому паттерну.
0
Я и вправду не понимаю суть решения, по этому и задал вопрос.
Если можно вызывать An()->action(); в любом месте программы, то в чем его отличие от вызова GetInstance(), как это решает проблему декларации использования класса Singleton в произвольном классе?
Задекларировать использование Singleton в классе, можно при помощи ссылки либо указателя на Singleton, также как автор писал An x; в классе Y.
Какое принципиальное отличия между использованием представленного шаблона An<> и простого указателя (ссылки)?
Может быть в продолжении это будет как-то более понятно, но в контексте данной статьи шаблон An мне кажется спорным.
Но в любом случае, автору спасибо за статью, пишите еще!
Если можно вызывать An()->action(); в любом месте программы, то в чем его отличие от вызова GetInstance(), как это решает проблему декларации использования класса Singleton в произвольном классе?
Задекларировать использование Singleton в классе, можно при помощи ссылки либо указателя на Singleton, также как автор писал An x; в классе Y.
Какое принципиальное отличия между использованием представленного шаблона An<> и простого указателя (ссылки)?
Может быть в продолжении это будет как-то более понятно, но в контексте данной статьи шаблон An мне кажется спорным.
Но в любом случае, автору спасибо за статью, пишите еще!
0
НЛО прилетело и опубликовало эту надпись здесь
Зарегистрируйтесь на Хабре , чтобы оставить комментарий
Использование паттерна синглтон