|
5. Одинак — Singleton
ADO в Delphi AJAX Android C++ CakePHP CMS COM CSS Delphi Flash Flex HTML Internet Java JavaScript MySQL PHP RIA SCORM Silverlight SQL UML XML Бази даних Веб-розробка Генетичні алгоритми ГІС Гітара Дизайн Економіка Інтелектуальні СДН Колір Масаж Математика Медицина Музика Нечітка логіка ООП Патерни Подання знань Розкрутка сайту, SEO САПР Сесії в PHP Системне програмування Системний аналіз Тестологія Тестування ПЗ Фреймворки Штучний інтелект
|
5. Одинак — Singleton
Уявімо, що нам потрібна глобальна логувальна система в програмі, також нам треба логувати наші повідомлення в якийсь один-єдиний файл, причому нумеруючи повідомлення послідовно, незалежно від того, з якого закутка програми вилетіла помилка. Як можна це зробити? Синглтон забезпечує існування єдиного екземпляру класу та єдиного доступу до нього. Клас, зображений нижче, демонструє просту реалізацію дизайн патерну Одинак (ця назва, чесно кажучи, звучить дещо «дико». Думаю, що може буде краще його називати Синглтон. Як вважаєте?) Уривок коду 5.1. Проста реалізація Синглтону
class LoggerSingleton
{
private LoggerSingleton() { }
private int _logCount = 0;
private static LoggerSingleton _loggerSingletonInstance = null;
public static LoggerSingleton GetInstance()
{
if (_loggerSingletonInstance == null)
{
_loggerSingletonInstance = new LoggerSingleton();
}
return _loggerSingletonInstance;
}
public void Log(String message)
{
Console.WriteLine(_logCount + ": " + message);
_logCount++;
}
}
Чіткі ознаки Одинака — приватний конструктор та доступ до єдиного, внутрішньо створеного екземпляру, здійснюваний через статичний метод. Уривок коду 5.2. Наша «важка робота» може виглядати так
public static void DoHardWork()
{
LoggerSingleton logger = LoggerSingleton.GetInstance();
HardProcessor processor = new HardProcessor(1);
logger.Log("Hard work started...");
processor.ProcessTo(5);
logger.Log("Hard work finished...");
}
Як бачимо метод використовує деякий клас HardProcessor. Що саме він наспраді робить, нас не дуже переймає, проте ми б хотіли, щоб було залоговано в місцях, коли екземпляр класу створився та коли виконувалися якісь підрахунки. Уривок коду 5.3. HardProcessor
class HardProcessor
{
private int _start;
public HardProcessor(int start)
{
_start = start;
LoggerSingleton.GetInstance().Log("Processor just created.");
}
public int ProcessTo(int end)
{
int sum = 0;
for (int i = _start; i <= end; ++i)
{
sum += i;
}
LoggerSingleton.GetInstance().Log(
"Processor just calculated some value: " + sum);
return sum;
}
}
А ось вивід програми:
0: Processor just created.
1: Hard work started...
2: Processor just calculated some value: 15
3: Hard work finished...
Я написав цей приклад, коли був у поїзді, і показав його свому другу, який також є програмістом. Він мені сказав, що я написав Моностейт. – «Я? Де?» Ми поглянули на код і виявилося, що тільки одна змінна в Синглтоні, яку я використовував, _logCount, була статичною в початковому варіанті, який я написав. (Зараз вона змінена на змінну інстансу, тому вгорі дійсно Синглтон).
То ж в чому різниця між Синглтоном і Моностейтом? Давайте глянемо на приклад ще раз. Швидше за все, що логгер не є таким тривіальним, можливо ви захочете додати функціональні зберігання останнього номера логу а при наступному зчитуванні починати нумерацію саме із того номера. Також ваша програма не така вже й проста і логування викликається не тільки із багатьох місць у коді, але і з багатьох потоків. Оскільки конструктор вашого класу працює із IO, то витрачається час на створення екземпляру класу. Таким чином GetInstance() через багатопоточність може привезти до ситуації, коли ви створите декілька екземплярів класу, а потім, що гірше, будете звертатися до різних логгерів! Напевно, не така вже і гарна ідея для вашої аплікації. Найпростіше вирішення проблеми це здійснити ініціалізацію екземпляру прямо у лінійці визначення змінної Синглтону, як зображено нижче. Уривок коду 5.4. Спрощене вирішення проблеми потокобезпечності
private static LoggerSingleton _loggerSingletonInstance = new LoggerSingleton();
Більш правильним, та елегантним буде таке рішення: Уривок коду 5.5. Потокобезпечний Синглтон
public class ThreadSafeLoggerSingleton
{
private ThreadSafeLoggerSingleton()
{
// Читаємо дані із якогось файлу і дістаємо номер останнього запису
// _logCount = вичитане значення
}
private int _logCount = 0;
private static ThreadSafeLoggerSingleton _loggerInstance;
private static readonly object locker = new object();
public static ThreadSafeLoggerSingleton GetInstance()
{
lock (locker)
{
if (_loggerInstance == null)
{
_loggerInstance = new ThreadSafeLoggerSingleton();
}
}
return _loggerInstance;
}
public void Log(String message)
{
Console.WriteLine(_logCount + ": " + message);
_logCount++;
}
}
Також часто використовується техніка Double-Checked Locking (DCL), яка не завжди працює. Прочитайте ось цю дуже хорошу статтю, вказану в зносках для повної картини потокобезпечності Синглтона на C#.
По матеріалам книги Андрія Будая "Дизайн патерни – просто, як двері". Матеріал розміщується за домовленістю з автором.
Зверніть увагу на додаткові посиланняЯкщо вас цікавить...Головний розділСторінки, близькі за змістомзагрузка...
|
Сторінки, близькі за змістом ![]() Шаблони проектування програмного забезпечення (англ. software design patterns) — ефективні способи вирішення задач проектування програмного забезпечення. Шаблон не є закінченим зразком, який можна безпосередньо транслювати в програмний код. Об'єктно-орієнтований шаблон найчастіше є зразком вирішення проблеми і відображає відношення між класами та об'єктами, без вказівки на те, як буде зрештою реалізоване це відношення. |
|
Copyright © 2008—2026 Портал Знань.
При використанні матеріалів посилання, для інтернет-ресурсів — гіперпосилання, на Znannya.org обов'язкове.
Зв'язок
|
НТУУ "КПІ" Інженерія програмного забезпечення КПІ Лабораторія СЕТ |
|