Студопедия
Главная страница | Контакты | Случайная страница

АвтомобилиАстрономияБиологияГеографияДом и садДругие языкиДругоеИнформатика
ИсторияКультураЛитератураЛогикаМатематикаМедицинаМеталлургияМеханика
ОбразованиеОхрана трудаПедагогикаПолитикаПравоПсихологияРелигияРиторика
СоциологияСпортСтроительствоТехнологияТуризмФизикаФилософияФинансы
ХимияЧерчениеЭкологияЭкономикаЭлектроника

Паттерн Singleton

Читайте также:
  1. Введение в паттерны проектирования
  2. Введение в паттерны проектирования
  3. Введение в паттерны проектирования
  4. Введение в паттерны проектирования
  5. Введение в паттерны проектирования
  6. Введение в паттерны проектирования
  7. Гдд Паттерны поведения
  8. Глава 1. Введение в паттерны проектирования
  9. Глава 3. Порождающие паттерны
  10. Глава 4. Структурные паттерны

возможные классы или экземпляры Singleton. Нужен лишь единый для всех классов Singleton интерфейс, включающий операции с реестром:

class Singleton { public:

static void Register(const char* name, Singleton*);

static Singleton* Instance ().; protected:

static Singleton* Lookup(const char* name); private:

static Singleton* „instance;

static List<NameSingletonPair>* „registry;

Операция Register регистрирует экземпляр класса Singleton под ука­занным именем. Чтобы не усложнять реестр, мы будем хранить в нем спи­сок объектов NameSingletonPair. Каждый такой объект отображает имя на одиночку. Операция Lookup ищет одиночку по имени. Предположим, что имя нужного одиночки передается в переменной среды:

Singleton* Singleton::Instance () { if („instance == 0) {

const char* singletonName = getenv("SINGLETON");

// пользователь или среда предоставляют это имя на стадии

// запуска программы

_instance = Lookup(singletonName); // Lookup возвращает 0, если такой одиночка не найден

return „instance;

В какой момент классы Singleton регистрируют себя? Одна из возмож­ностей - конструктор. Например, подкласс MySingleton мог бы работать так:

MySingleton::MySingleton() {

Singleton::Register("MySingleton", this); }

Разумеется, конструктор не будет вызван, пока кто-то не инстанцирует класс, но ведь это та самая проблема, которую паттерн одиночка и пытается разрешить! В C++ ее можно попытаться обойти, определив статический эк­земпляр класса My Single ton. Например, можно вставить строку

static MySingleton theSingleton; в файл, где находится реализация MySingleton.

Теперь класс Singleton не отвечает за создание одиночки. Его основной

обязанностью становится обеспечение доступа к объекту-одиночке из


 

Порождающие паттерны

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

Пример кода

Предположим, нам надо определить класс MazeFactory для создания лаби­ринтов, описанный на стр. 99. MazeFactory определяет интерфейс для построения различных частей лабиринта. В подклассах эти операции могут переопределять­ся, чтобы возвращать экземпляры специализированных классов продуктов, на­пример объекты BombedWall, а не просто Wall.

Существенно здесь то, что приложению Maze нужен лишь один экземпляр фабрики лабиринтов и он должен быть доступен в коде, строящем любую часть лабиринта. Тут-то паттерн одиночка и приходит на помощь. Сделав фабрику MazeFactory одиночкой, мы сможем обеспечить глобальную доступность объек­та, представляющего лабиринт, не прибегая к глобальным переменным.

Для простоты предположим, что мы никогда не порождаем подклассов от MazeFactory. (Чуть ниже будет рассмотрен альтернативный подход.) В C++ для того, чтобы превратить фабрику в одиночку, мы добавляем в класс MazeFactory статическую операцию Instance и статический член _instance, в котором бу­дет храниться единственный экземпляр. Нужно также сделать конструктор защи­щенным, чтобы предотвратить случайное инстанцирование, в результате которо­го будет создан лишний экземпляр:

class MazeFactory { public:

static MazeFactory* Instance();

// здесь находится существующий интерфейс protected:

MazeFactory(); private:

static MazeFactory* „instance; };

Реализация класса такова:

MazeFactory* MazeFactory::_instance = 0;

MazeFactory* MazeFactory::Instance 0 { if (_instance == 0) {

_instance = new MazeFactory; I return _instance;

}

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


 

Паттерн Singleton

подкласс MazeFactory в зависимости от значения данной переменной. Лучше

всего поместить код в операцию Instance, поскольку она уже и так инстанциру-ет MazeFactory:

MazeFactory* MazeFactory::Instance () { if (_instance == 0) {

const char* mazeStyle = getenv("MAZESTYLE");

if (strcmp(mazeStyle, "bombed") == 0) { „.instance = new BombedMazeFactory;

} else if (strcmp(mazeStyle, "enchanted") == 0) { _instance = new EnchantedMazeFactory;

//... другие возможные подклассы

} else { // по умолчанию

_instance = new MazeFactory; } j

return _instance; }

Отметим, что операцию Instance нужно модифицировать при определении каждого нового подкласса MazeFactory. В данном приложении это, может быть, и не проблема, но для абстрактных фабрик, определенных в каркасе, такой под­ход трудно назвать приемлемым.

Одно из решений - воспользоваться принципом реестра, описанным в разде­ле «Реализация». Может помочь и динамическое связывание, тогда приложению не нужно будет загружать все неиспользуемые подклассы.

Известные применения

Примером паттерна одиночка в Smalltalk-80 [РагЭО] является множество из­менений кода, представленное классом Change Set. Более тонкий пример - это отношение между классами и их метаклассами. Метаклассом называется класс класса, каждый метакласс существует в единственном экземпляре. У метакласса нет имени (разве что косвенное, определяемое экземпляром), но он контролирует свой уникальный экземпляр, и создать второй обычно не разрешается.

В библиотеке Interviews для создания пользовательских интерфейсов [LCI+92] - паттерн одиночка применяется для доступа к единственным экземпля­рам классов Session (сессия) и WidgetKit (набор виджетов). Классом Session определяется главный цикл распределения событий в приложении. Он хранит пользовательские настройки стиля и управляет подключением к одному или не­скольким физическим дисплеям. WidgetKit - это абстрактная фабрика для определения внешнего облика интерфейсных виджетов. Операция Widget­Kit:: instance () определяет конкретный инстанцируемый подкласс WidgetKit на основе переменной среды, которую устанавливает Session. Аналогичная опе­рация в классе Session «выясняет», поддерживаются ли монохромные или цвет­ные дисплеи, и соответственно конфигурирует одиночку Session.




Дата добавления: 2015-09-11; просмотров: 155 | Поможем написать вашу работу | Нарушение авторских прав

Паттерн Factory Method | Порождающие паттерны | Паттерн Prototype | Порождающие паттерны | Порождающие паттерны | Реализация | Паттерн Prototype | Паттерн Prototype | Паттерн Singleton | Результаты |


lektsii.net - Лекции.Нет - 2014-2025 год. (0.008 сек.) Все материалы представленные на сайте исключительно с целью ознакомления читателями и не преследуют коммерческих целей или нарушение авторских прав