| Приведенный класс имеет закрытые конструктор по умолчанию и деструктор, а также наследует boost::noncopyable. Таким образом ни пользователь, ни наследники класса не смогут самостоятельно создавать или удалять объекты данного класса. Создание и удаление происходит в функциях initialize и shutdown. Иными словами, мы имеем все гарантии того, что в программе будет существовать не более одного объекта класса window. Закрытый оператор присваивания избавит от проблем, связанных с присваиванием самому себе. Как вы наверно уже заметили, единственный объект хранится по простому указателю, а не, скажем, по std::auto_ptr, и это не случайно. Наш синглтон имеет закрытый деструктор, и std::auto_ptr просто не сможет удалить объект. А не подружить ли синглтон со смарт-поинтером? Нет — ведь в таком случае и у пользователя появится возможность оперировать смарт-поинтерами на синглтон. Да, пользователь не сможет создавать объекты, однако у него будет возможность конструировать смарт-поинтеры от указателя, полученного, например, с помощью &window::instance(). Конечно, такой случай выглядит весьма сомнительно, однако вспомним старый анекдот — после запирания входной двери на цербер, французский, английский и израильский замок, дополнительно закрыть на швабру все же не помешает. | |
| Существует четыре способа инициализации и уничтожения синглтона:- Инициализация и уничтожение выполняются соответствующими свободными или статическими функциями;
- Инициализация и уничтожение выполняются посредством идиомы владения. В функции-точке входа на стеке объявляется объект, инициализирующий синглтон в конструкторе, и уничтожающий его в деструкторе. На мой взгляд это наиболее разумный вариант;
- Так называемая lazy-инициализация. Инициализация происходит при первом обращении к синглтону, уничтожение — вызовом соответствующей функции. Достоинство этого способа в том, что если пользователь не использует синглтон, то и не выделяются никакие ресурсы. Недостаток состоит в том, что если в системе присутствует несколько синглтонов, использующих друг друга, то может возникнуть ситуация, при которой сингтоны должны быть проинициализированны в определенном порядке, и вам придется выстраивать этот порядок искусственным путем;
- Синглтон Меерса. Синглтон инициализируется в конструкторе, уничтожается в деструкторе и кроме того, сам синглтон является статическим объектом. В данном случае проблема всего одна — стандарт ничего не говорит о порядке конструирования статических объектов из разных единиц компиляции. Если у вас будет несколько сингтонов, использующих друг друга, то скорее всего этот метод приведет к проблемам.
| |
| Что касается недостатков паттерна — он, недостаток, собственно, один. И кроется этот недостаток даже не в самом паттерне, а в недальновидности программиста. Дело в том, что не так просто понять, действительно ли в программе будет только один экземпляр класса. Посмотрим на наш экранчик телефона. Сегодня наш синглтон прекрасно справляется с возложенной на него задачей. Но представьте себе, что завтра к нам придет начальник и скажет, что компания выпустила новую модель телефона с двумя экранами, и нужно, как это всегда бывает, по-быстрому адаптировать существующую библиотеку под новый телефон. Вот тут и начнутся проблемы, которых, кстати говоря, можно было очень легко избежать, попросту не делая класс синглтоном. | |
| Что делать, если используемое API подталкивает вас к использованию синглтона? В этом случае лучше всего оперировать объектами так, как будто они не являются синглтонами, если это, конечно же, не противоречит здравому смыслу. Например, API для работы с камерой сотового телефона может навязывать вам работу с синглтоном, однако ваши адаптеры могут «делать вид», что камера не является синглтоном: | |