Прославлена глобальна змінна - стає прославленим глобальним класом. Деякі кажуть, що порушують об'єктно-орієнтований дизайн.
Надайте мені сценарії, окрім старого хорошого лісоруба, де є сенс використовувати синглтон.
Прославлена глобальна змінна - стає прославленим глобальним класом. Деякі кажуть, що порушують об'єктно-орієнтований дизайн.
Надайте мені сценарії, окрім старого хорошого лісоруба, де є сенс використовувати синглтон.
Відповіді:
На моєму прагненні до правди я виявив, що насправді дуже мало "прийнятних" причин використовувати Singleton.
Однією з причин, яка має тенденцію з'являтися знову і знову в інтернетах, - це клас "реєстрації" (який ви згадали). У цьому випадку Singleton може бути використаний замість одного примірника класу, тому що клас журналу, як правило, потрібно використовувати знову і знову рекламні нудоти кожного класу в проекті. Якщо кожен клас використовує цей клас реєстрації, введення залежності стає громіздким.
Ведення журналів - конкретний приклад "прийнятного" Singleton, оскільки він не впливає на виконання вашого коду. Вимкнути журнал, виконання коду залишається колишнім. Увімкніть це, те саме. Місько викладає це так у Root Cause of Singletons : "Інформація тут протікає в один бік: з вашої програми в реєстратор. Навіть незважаючи на те, що реєстратори є глобальним станом, оскільки жодна інформація не перетікає з реєстраторів у вашу програму, реєстратори є прийнятними".
Я впевнений, що є й інші поважні причини. Алекс Міллер у " Шаблонах, які я ненавиджу ", розмови про локатори обслуговування та інтерфейс клієнта також можуть бути "прийнятним" вибором.
Детальніше читайте на Singleton Я тебе люблю, але ти мене зводиш.
Кандидат в одиночку повинен відповідати трьом вимогам:
Якщо ваш запропонований Singleton має лише одну або дві з цих вимог, редизайн майже завжди є правильним варіантом.
Наприклад, навряд чи зателефонують із спілера принтера з більш ніж одного місця (меню «Друк»), тому ви можете використовувати мутекси для вирішення паралельної проблеми доступу.
Простий реєстратор - найочевидніший приклад можливого дійсного Singleton, але це може змінитися за допомогою більш складних схем реєстрації.
Читання файлів конфігурації, які слід читати лише під час запуску, та інкапсулюючи їх у Singleton.
Properties.Settings.Default
.NET.
Ви використовуєте одиночний ключ, коли вам потрібно керувати спільним ресурсом. Наприклад, шпулер принтера. У вашій програмі має бути лише один екземпляр спілера, щоб уникнути суперечливого запиту на один і той же ресурс.
Або підключення до бази даних, або файловий менеджер тощо.
Читати лише одиночні кнопки, які зберігають деякий глобальний стан (мова користувача, довідковий шлях, шлях програми). Будьте обережні, використовуючи одиночні кнопки для управління бізнес-логікою - сингл майже завжди стає кінцевим
Управління з'єднанням (або пулом з'єднань) до бази даних.
Я також використовував би його для отримання та зберігання інформації у зовнішніх файлах конфігурації.
Одним із способів використання синглтона є покриття екземпляра, коли повинен бути один "брокер", що контролює доступ до ресурсу. Синглтони хороші в реєстраторах, тому що вони посередники отримують доступ до, скажімо, файлу, до якого можна писати виключно. Щось таке, як ведення журналу, вони пропонують спосіб абстрагування запису чимось на зразок файлу журналу - ви можете зафіксувати механізм кешування до свого сингтона та ін.
Також подумайте про ситуацію, коли у вас є програма з багатьма вікнами / потоками / тощо, але яка потребує єдиної точки зв'язку. Я колись використовував один для контролю завдань, які хотів запустити мою програму. Сінглтон відповідав за серіалізацію робочих місць та показ їх статусу в будь-якій іншій частині програми, яка зацікавилась. У такому сценарії ви можете розглядати синглтон як щось на зразок класу "сервер", що працює у вашій програмі ... HTH
Синглтон повинен використовуватися при управлінні доступом до ресурсу, яким поділяється вся програма, і це може бути руйнівним, щоб потенційно мати кілька екземплярів одного класу. Переконайтеся, що безпека доступу до потоку загальних ресурсів є одним дуже хорошим прикладом того, як такий зразок може бути життєво важливим.
Використовуючи Singletons, ви повинні переконатися, що ви випадково не приховуєте залежності. В ідеалі одиночні кнопки (як і більшість статичних змінних у додатку) встановлюються під час виконання коду ініціалізації для програми (статичний недійсний Main () для виконуваних файлів C #, статичний недійсний main () для виконуваних файлів Java) і потім передаються в всі інші класи, які вимагають цього. Це допомагає вам зберегти заповітність.
Практичний приклад синглтону можна знайти в Test :: Builder , класі, який підтримує практично кожен сучасний модуль тестування Perl. Сингл-тест Test :: Builder зберігає та брокерів стан та історію тестового процесу (історичні результати тестування, підраховує кількість запущених тестів), а також такі речі, як, куди йде тестовий результат. Це все необхідне для узгодження декількох модулів тестування, написаних різними авторами, для спільної роботи в одному тестовому сценарії.
Історія тесту :: Одногранник будівельника є навчальним. Виклик new()
завжди дає вам один і той же об’єкт. По-перше, всі дані зберігалися у вигляді змінних класів, що нічого не має в самому об'єкті. Це працювало, поки я не хотів перевірити Test :: Builder із самим собою. Тоді мені знадобилися два об’єкти Test :: Builder, одна установка як манекен, щоб захопити та перевірити його поведінку та вихід, а один - справжній тестовий об’єкт. У цей момент Test :: Builder був перероблений на реальний об'єкт. Одиничний об'єкт зберігався як дані класу і new()
завжди повертав його. create()
було додано, щоб зробити свіжий об'єкт і включити тестування.
В даний час користувачі хочуть змінити деякі поведінки Test :: Builder у своєму модулі, але інші залишити в спокої, в той час як історія тестів залишається спільною для всіх модулів тестування. Зараз відбувається монолітний об'єкт Test :: Builder, який розбивається на більш дрібні фрагменти (історія, вихід, формат ...) за допомогою екземпляра Test :: Builder, який збирає їх разом. Тепер тест :: Builder більше не повинен бути одиноким. Його компоненти, як і історія, можуть бути. Це висуває невгамовну необхідність сингла до рівня. Це надає більшої гнучкості користувачеві для змішування та співпадіння творів. Менші об'єкти одиночної форми тепер можуть просто зберігати дані, і їх об'єкти, що містять, вирішують, як їх використовувати. Він навіть дозволяє не тестувати :: Builder клас, щоб грати разом, використовуючи тест: :: Історія будівельника та виведення одиночних клавіш.
Здається, існує поштовх і координація між координацією даних та гнучкістю поведінки, яку можна пом'якшити, поставивши сингтон навколо лише спільних даних з найменшою кількістю поведінки, щоб забезпечити цілісність даних.
Коли ви завантажуєте об’єкт властивостей конфігурації або з бази даних, або з файлу, це допомагає мати його як сингл; немає жодної причини тримати повторне читання статичних даних, які не змінюватимуться під час роботи сервера.
Ви можете використовувати Singleton при реалізації схеми State (таким чином, як показано в книзі GoF). Це пояснюється тим, що конкретні державні класи не мають власного стану і виконують свої дії з точки зору контекстного класу.
Ви також можете зробити абстрактний завод однотонним.
setState()
відповідальності за прийняття політики щодо створення держави. Це допомагає, якщо ваша мова програмування підтримує шаблони або дженерики. Замість Singleton можна використовувати шаблон Monostate , коли інстанціювання об'єкта стану закінчується повторним використанням того ж глобального / статичного об'єкта стану. Синтаксис зміни стану може залишатися незмінним, оскільки ваші користувачі не повинні знати, що інстанційований стан є Monostate.
Спільні ресурси Особливо для PHP, класу баз даних, шаблонного класу та глобального класу змінних депо. Всі вони повинні бути спільними для всіх модулів / класів, які використовуються протягом коду.
Це справжнє використання об'єкта -> клас шаблону містить шаблон сторінки, який створюється, і він формується, додається, змінюється модулями, що додають до виводу сторінки. Це повинно зберігатися як єдиний екземпляр, щоб це могло статися, і те саме стосується баз даних. Завдяки спільній синхронізації бази даних, усі класи модулів можуть отримати доступ до запитів та отримати їх, не потребуючи їх повторного використання.
Сингл-депо глобальної змінної депо забезпечує вам глобальне, надійне та зручне використання змінного депо. Це дуже прибирає ваш код. Уявіть, що всі значення конфігурації в масиві в одиночному вигляді є:
$gb->config['hostname']
або з усіма мовними значеннями в масиві, наприклад:
$gb->lang['ENTER_USER']
Зрештою, запустивши код сторінки, ви отримаєте, скажімо, вже зрілий:
$template
Синглтон, $gb
синглтон, який має масив lang для заміни в нього, і весь вихід завантажений і готовий. Ви просто замінюєте їх на ключі, які зараз є у значенні сторінки об’єкта зрілих шаблонів, а потім подаєте їх користувачеві.
Велика перевага цього в тому, що ви можете робити будь-яку вподобану післяобробку будь-що. Ви можете передати всі мовні значення для перекладу google або іншої служби перекладу та отримати їх назад, а також замінити їх на місця, перекладені, наприклад. або, ви можете замінити в структурах сторінок або
Конфігурувати конкретні проблеми інфраструктури як одиночні або глобальні змінні може бути дуже прагматично. Мій улюблений приклад цього - фреймворки Dependency Injection, які використовують одиночні кнопки, щоб діяти в якості точки з'єднання з рамкою.
У цьому випадку ви приймаєте залежність від інфраструктури для спрощення використання бібліотеки та уникнення зайвих складностей.
Я використовую його для об'єкта параметрів командного рядка, що інкапсулює, коли працює з модулями, що підключаються. Основна програма не знає, які параметри командного рядка для модулів, які завантажуються (і не завжди навіть знає, які модулі завантажуються). наприклад, основні навантаження A, яким не потрібні самі параметри (тому чому він повинен займати додатковий вказівник / посилання / що завгодно, я не впевнений - схоже на забруднення), потім завантажує модулі X, Y і Z. Два з них, скажімо, X і Z, потрібні (або прийняти) параметри, тому вони передзвонюють в командний рядок сингтон, щоб повідомити, які параметри приймати, і під час виконання вони передзвонюють, щоб дізнатися, чи дійсно користувач вказав якісь їх.
Багато в чому синглтон для обробки параметрів CGI працював би так само, якщо ви використовуєте лише один процес за запитом (інші методи mod_ * цього не роблять, тому це буде погано - таким чином, аргумент, який говорить, що ви не повинні ' t використовувати одиночні кнопки у світі mod_cgi у випадку, якщо ви портуєте до mod_perl або будь-якого іншого світу).
Можливо, приклад з кодом.
Тут ConcreteRegistry - сингл-покер у грі в покер, який дозволяє поведінці аж до дерева пакетів отримати доступ до декількох основних основних інтерфейсів гри (тобто, фасадів для моделі, виду, контролера, оточення тощо):
http://www.edmundkirwan.com/servlet/fractal/cs1/frac-cs40.html
Ред.
1 - коментар до першої відповіді:
Я не згоден зі статичним класом Logger. це може бути практично для реалізації, але воно не може бути заміненим для тестування одиниць. Статичний клас не може бути замінений тестовим подвійним. Якщо ви не зробите тест, ви не побачите тут проблеми.
2 - Я намагаюся не створювати синглів вручну. Я просто створюю простий об'єкт з конструкторами, які дозволяють мені вводити в об’єкт співпрацівників. Якщо мені знадобився синглтон, я б використовував рамку огляду залежностей (Spring.NET, Unity для .NET, Spring для Java) або якусь іншу.
ILogger logger = Logger.SingleInstance();
де цей метод є статичним і він повертає статично збережений екземпляр ILogger. Ви використовували приклад "структури введення залежності". Майже всі контейнери DI є однотонними; їх конфігурації визначаються статично і в кінцевому підсумку доступні / зберігаються в одному інтерфейсі постачальника послуг.