Що так погано в одиночних? [зачинено]


1982

Картина Сінглтона є повністю сплаченим членом GoF «s моделея книги , але в останній час , здається , досить сиріт в світі розробника. Я все ще використовую досить багато одиночних клавіш, особливо для фабричних занять , і, хоча ви повинні бути обережними щодо питань багатопотокової роботи (як і будь-який клас насправді), я не розумію, чому вони такі жахливі.

Переповнення стека особливо припускає, що всі згодні з тим, що Singletons є злими. Чому?

Будь ласка, підтримайте свої відповіді " фактами, посиланнями чи певною експертизою "


6
Я мушу сказати, що використання одинарного дизайну нещодавно спалило мене, коли я намагався адаптувати код. Коли я це роблю у вільний час, я майже лінуюся це відреагувати. Погані новини для продуктивності.
Марцін

71
У відповідях є багато "мінусів", але я також хотів би побачити кілька хороших прикладів того, коли модель хороша, щоб протиставити погану ...
DGM

50
Я написав повідомлення в блозі на цю тему кілька місяців тому: jalf.dk/blog/2010/03/… - і дозвольте мені просто сказати це прямо. Я особисто не можу придумати єдину ситуацію, коли сингтон - це правильне рішення. Це не означає, що такої ситуації не існує, але ... називати їх рідкісними - це заниження.
джельф

8
@AdamSmith це не означає, що потрібно , але це означає, що ти можеш отримати доступ до нього так. І якщо ви не збираєтесь до нього звертатися так, то мало підстав зробити його в першу чергу синглом. Тож ваш аргумент фактично "немає жодної шкоди зробити одинакову, якщо ми не ставимось до неї як до синглів. Так, чудово. Моя машина також не забруднює, якщо я не їзжу в ній. Але тоді простіше просто не придбайте автомобіль в першу чергу.;) (повне розкриття: у мене фактично немає машини)
затримка

35
Найгірша частина всієї цієї теми полягає в тому, що люди, які ненавидять одиноких, рідко дають конкретні пропозиції, що використовувати замість цього. Наприклад, посилання на статті в журналах та блоги, що публікуються в самій статті, про все, через цю статтю ТА, продовжують розповідати про те, чому б не використовувати одиночні кнопки (і всі вони є чудовими причинами), але вони надзвичайно тонкі для заміни. Хоча багато ручної роботи. Ті з нас, які намагаються навчити нових програмістів, чому б не використовувати одиночні, не мають багато хороших сторонніх контрприкладів, на які можна вказати, лише надумані приклади. Це стомлює.
Ti Strga

Відповіді:


1293

Перефразоване від Брайана Кнопка:

  1. Вони, як правило, використовуються як глобальний екземпляр, чому це так погано? Тому що ви ховаєте залежності свого додатка у своєму коді, а не виставляти їх через інтерфейси. Зробити щось глобальне, щоб уникнути його передачі - кодовий запах .

  2. Вони порушують принцип єдиної відповідальності : завдяки тому, що вони контролюють власне створення та життєвий цикл.

  3. Вони за своєю суттю призводять до того, що код щільно з'єднаний . Це робить фальсифікацію їх під тестом у багатьох випадках досить складною.

  4. Вони зберігають стан протягом усього життя програми. Ще одне враження від тестування, оскільки у вас може виникнути ситуація, коли потрібно замовити тести, що для одиничних тестів є великим "ні". Чому? Оскільки кожен одиничний тест повинен бути незалежним від іншого.


324
Я не згоден з вами. Оскільки для коментарів дозволено лише 600 символів, я написав повідомлення в блозі, щоб прокоментувати це, перегляньте посилання нижче. jorudolph.wordpress.com/2009/11/22/singleton-consisitions
Йоханнес Рудольф

61
З точки зору 1 і 4, я вважаю, що одиночні кнопки є корисними і насправді майже ідеальними для кешування даних (особливо з БД). Збільшення продуктивності далеко вбік складності, пов'язані з тестуванням модульних одиниць.
Дай Бок

56
@Dai Bok: "кешування даних (особливо з БД)" використовуйте шаблон проксі для цього ...
paxos1977

55
Ого, чудові відгуки. Я, мабуть, використовував тут занадто агресивні формулювання, тому, будь ласка, майте на увазі, що я відповідав на негативно налаштоване питання. Моя відповідь мала бути коротким списком "антитіл", які виникають внаслідок поганого використання Singleton Повне розкриття; Я теж час від часу використовую Singletons. Існують більш нейтрально поставлені запитання щодо ТА, які могли б зробити чудові форуми, коли Singletons можна вважати гарною ідеєю. Наприклад, stackoverflow.com/questions/228164/…
Джим Бергер

21
Вони не такі великі для кешування у багатопотоковому середовищі. Ви можете легко перемогти кеш із кількома потоками, що ведуть боротьбу за обмежений ресурс. [підтримується
одиноким

449

Сінглтони вирішують одну (і лише одну) задачу.

Суперечка ресурсів.

Якщо у вас є якийсь ресурс, це

( 1 ) може мати лише один екземпляр, і

( 2 ) вам потрібно керувати цим єдиним екземпляром,

вам потрібен сингл .

Прикладів не так багато. Файл журналу - великий. Ви не хочете просто відмовитися від одного файлу журналу. Ви хочете належним чином очистити, синхронізувати та закрити. Це приклад єдиного спільного ресурсу, яким потрібно керувати.

Рідко буває, що вам потрібен сингл. Причина, що вони погані, полягає в тому, що вони відчувають себе глобальними, і вони є повністю платним членом книги GoF Design Patterns .

Коли ви думаєте, що вам потрібен глобальний, ви, мабуть, робите жахливу помилку в дизайні.


43
Апаратне забезпечення також є прикладом, чи не так? Вбудовані системи мають багато обладнання, яке може використовувати одиночні кнопки - чи, можливо, одне велике? <grin>
Джефф

170
Повністю згоден. Існує багато рішучих "ця практика погана", розмовляючи навколо без будь-якого визнання, що практика може мати своє місце. Часто така практика є лише "поганою", оскільки її часто зловживають. З малюнком Singleton немає нічого суттєвого, доки він належним чином застосований.
Дамовіса,

53
Справжні, за принципом, одиночні кнопки дуже рідкісні (а черга принтерів, безумовно, не одна, а також файл журналу - див. Log4j). Частіше апаратне забезпечення - це синглтон за збігом, а не за принципом. Все апаратне забезпечення, підключене до ПК, у кращому випадку - випадковий синглтон (думаю, кілька моніторів, мишей, принтерів, звукових карт). Навіть детектор частинок в 500 мільйонів доларів є одинаковим за збігом обставин і бюджетними обмеженнями - які не застосовуються в програмному забезпеченні, таким чином: не однотонний. У телекомунікаціях ні номер телефону, ні фізичний телефон не є одинаковими (подумайте, ISDN, кол-центр).
digitalarbeiter

23
Обладнання може мати лише один примірник різних ресурсів, але апаратне забезпечення - це не програмне забезпечення. Немає жодних причин, щоб один послідовний порт на платі розробки мадерувався як Singleton. Дійсно, його моделювання лише ускладнить перехід на нову плату, яка має два порти!
dash-tom-bang

19
Отже, ви б написали два однакових класи, дублюючи багато коду, просто щоб у вас було два сингтона, що представляють два порти? Як щодо простого використання двох глобальних об’єктів SerialPort? А як щодо взагалі не моделювати обладнання як класи? І чому б ви використовували одиночні кнопки, що також передбачає глобальний доступ? Чи хочете, щоб кожна функція у вашому коді мала доступ до послідовного порту?
jalf

352

Деякі кодові комори розглядають їх як просто прославлену глобальну. Так само, як багато людей ненавидять вислів goto, є й інші, які ненавидять ідею коли-небудь використовувати глобальний . Я бачив, як декілька розробників намагаються уникати глобальних ситуацій, оскільки вони розглядали можливість використання одного як визнання невдачі. Дивно, але правда.

На практиці шаблон Singleton - це лише техніка програмування, яка є корисною частиною вашої набір інструментів. Час від часу ви можете виявити, що це ідеальне рішення, тому використовуйте його. Але використовувати його просто так, що ви можете похвалитися тим, що використовувати шаблон дизайну так само нерозумно, як і відмовлятися від його використання коли-небудь, оскільки він просто глобальний .


17
Невдача, яку я бачу в Сінглтоні, полягає в тому, що люди використовують їх замість глобальних, оскільки вони якось "кращі". Проблема полягає в тому, що речі, які Сінглтон приносить до столу в цих випадках, не мають значення. (Construct-on-first-use - тривіально реалізовуватись, наприклад, у не одиночному форматі, навіть якщо він фактично не використовує конструктор для цього.)
dash-tom-bang

21
Причина "ми" дивимось на них в тому, що "ми" дуже часто бачимо, як вони використовуються неправильно, і занадто часто. "Ми" знаємо, що у них є місце їхньої причини.
Bjarke Freund-Hansen

5
@Phil, ви заявляли, "час від часу ви можете виявити, що це ідеальне рішення, і тому використовуйте його". Добре, тож саме в такому випадку ми знайдемо єдину корисну?
Pacerier

22
@Pacerier, коли виконуються всі наступні умови: (1) вам потрібна лише одна річ, (2) вам потрібно передавати цю річ як аргумент у великій кількості викликів методу, (3) ви готові прийняти вірогідність того, що коли-небудь доведеться перетворити рефактор в обмін на негайне зменшення розміру та складності вашого коду, не проходячи всюди прокляту річ.
antinome

18
Я не відчуваю, що це відповідає на що-небудь, воно просто говорить, що «іноді це може підходити, інше - може». Гаразд, але чому, і коли? Що робить цю відповідь більш ніж аргументом поміркованості ?
Гільденстерн

219

Місько Гевери від Google має кілька цікавих статей саме на цю тему ...

Singleton - патологічні брехуни, має приклад тестування одиниць, який ілюструє, як одиночні можуть ускладнити з'ясування ланцюгів залежностей та запустити чи протестувати додаток. Це досить екстремальний приклад зловживань, але пункт, який він робить, все ще діє:

Синглтони - це не що інше, як глобальна держава. Глобальна держава робить це, щоб ваші об'єкти могли таємно влаштовувати речі, які не задекларовані в їх API, і, як результат, Singletons перетворюють ваші API в патологічних брехунів.

Там, де всі Singletons Gone, вказується на те, що введення залежності залежно від того, щоб отримати екземпляри до конструкторів, які вимагають їх, що полегшує основну потребу позаду поганих, глобальних синглтонів, описаних у першій статті.


8
Статті Місько на цю тему - це найкраще, що зараз відбувається навколо неї.
Кріс Майєр

22
Перше посилання насправді не вирішує проблему з однотонними, а скоріше передбачає статичну залежність всередині класу. Можна виправити даний приклад, передавши параметри, але все одно використовувати одиночні.
DGM

17
@DGM: Саме так - насправді існує величезний логічний розрив між частиною статті "обгрунтування" та частиною "Singletons є причиною".
Харпер Шелбі

1
Стаття про CreditCard Міско є крайнім прикладом неправильного використання цього шаблону.
Олексій

2
Читання другої статті Singletons - насправді частина описаної об'єктної моделі. Однак замість того, щоб бути доступними у всьому світі, вони є приватними для заводських об'єктів.
FruitBreak

121

Я думаю, що плутанина викликана тим, що люди не знають реального застосування схеми Сінглтона. Я не можу це підкреслити достатньо. Синглтон - це не візерунок, який слід обертати глобалами. Шаблон Singleton слід використовувати лише для того, щоб гарантувати існування одного та лише одного примірника даного класу під час виконання.

Люди думають, що Сінглтон є злом, тому що вони використовують його для глобальних. Саме через цю плутанину Сінглтон дивиться вниз. Будь ласка, не плутайте одиночних та глобальних. Якщо використовувати його за призначенням, призначеному для нього, ви отримаєте надзвичайну користь від шаблону Singleton.


20
Що це за один екземпляр, доступний у всій програмі? Ой. Глобальний . "Синглтон не є шаблоном для загортання глобальних" або є наївним, або оманливим, так як за визначенням шаблон обмотує клас навколо глобального екземпляра.
cHao

26
Звичайно, ви можете створити один екземпляр класу при запуску програми та ввести цей екземпляр через інтерфейс у все, що його використовує. Реалізація не повинна перейматися тим, що може бути лише одна.
Скотт Вітлок

4
@Dainius: Зрештою, цього немає. Звичайно, ви не можете довільно замінити екземпляр іншим. (За винятком тих моментів, які викликають обличчя, коли ви це робите . Я насправді раніше бачив setInstanceметоди.) Але це навряд чи має значення - той віні, який "потрібен" синглу, також не знав чудової речі про інкапсуляцію чи що не так змінна глобальна держава, тож він корисно (?) надав сеттерів для кожного. неодружений поле. (І так, це трапляється. Дуже багато . Майже кожен сингтон, який я коли-небудь бачив у дикій природі, був замисленим за дизайном, і часто це
зухвало

4
@Dainius: Значною мірою ми вже маємо. "Віддавайте перевагу складу над спадщиною" вже досить давно. Якщо успадкування - це, мабуть, найкраще рішення, проте ви, звичайно, можете його використовувати. Те ж саме і з одиночними, глобальними, нитковими, gotoі т. Д. Вони можуть працювати у багатьох випадках, але, чесно кажучи, "працює" недостатньо - якщо ви хочете суперечити загальноприйнятій мудрості, вам краще зможете продемонструвати, як ваш підхід це краще , ніж звичайні розчини. І я ще не бачив такого випадку за схемою Сінглтона.
cHao

3
Щоб ми не говорили один про одного, я не просто про глобально доступний екземпляр. Для цього є безліч випадків. Те, про що я говорю (особливо, коли я кажу "capital-S Singleton"), - це модель Singleton GoF, яка вбудовує цей єдиний глобальний екземпляр у сам клас, викриває його за допомогою getInstanceподібного або названого методу та запобігає існуванню друга інстанція. Відверто кажучи, в цей момент у вас може бути навіть не один екземпляр.
cHao

72

Дуже погана річ про одиночних - це те, що ви не можете їх легко розширити. Ви, в основному, повинні будувати якусь схему декораторів чи якусь подібну річ, якщо хочете змінити їх поведінку. Крім того, якщо одного дня ви хочете скористатися кількома способами зробити це одне, змінити це може бути досить болісно, ​​залежно від того, як ви викладете свій код.

Одне зауважте, якщо ви використовуєте одиночні кнопки, спробуйте передати їх тому, кому вони потрібні, а не матимуть доступ до нього безпосередньо ... Інакше, якщо ви коли-небудь вирішите мати кілька способів робити те, що робить одиночний, це буде досить важко змінити, оскільки кожен клас вкладає залежність, якщо він отримує доступ до одинарного безпосередньо.

Так в основному:

public MyConstructor(Singleton singleton) {
    this.singleton = singleton;
}

а не:

public MyConstructor() {
    this.singleton = Singleton.getInstance();
}

Я вважаю, що така схема називається ін'єкцією залежності і, як правило, вважається хорошою справою.

Як і будь-яка закономірність ... Поміркуйте над цим і подумайте, чи його використання в даній ситуації є недоцільним чи ні ... Правила зазвичай порушуються, і шаблони не повинні без особливих зусиль застосовуватися мимоволі.


17
Хе, якщо ви робите це скрізь, то вам також доведеться скрізь проходити посилання на сингелтон, і, таким чином, у вас більше немає одинаків. :) (Що, як правило, хороша річ IMO.)
Bjarke Freund-Hansen

2
@ BjarkeFreund-Hansen - Дурниця, про що ти говориш? Синглтон - це просто екземпляр класу, який встановлюється один раз. Посилання на такий синглтон не копіює фактичний об'єкт, він лише посилається на нього - у вас все одно є той самий об’єкт (читайте: Singleton).
М. Мімпен

2
@ M.Mimpen: Ні, Сінглтон-капітал-S (про що йдеться тут) - це екземпляр класу, який (а) гарантує, що коли-небудь існуватиме лише один екземпляр, і (b) доступ до нього здійснюється через власний клас вбудована глобальна точка доступу. Якщо ви заявили, що нічого не повинно дзвонити getInstance(), то (б) вже не зовсім так.
cHao

2
@cHao Я не слідкую за тобою, або ти не розумієш, до кого я коментую - що стосується Б'ярке Фрейнд-Хансена. Bjarke стверджує, що наявність декількох посилань на однотонний результат має кілька синглів. Це, звичайно, неправда, оскільки немає глибоких копій.
М. Мімпен

6
@ M.Mimpen: Я вважаю, що його коментар стосується семантичного ефекту. Після того, як ви забороняєте звертатись getInstance(), ви фактично викинули єдину корисну відмінність між шаблоном Сінглтона і звичайною посиланням. Що стосується решти коду, одиничність вже не є властивістю. Тільки, хто телефонує, getInstance()повинен знати або навіть дбати про те, скільки існує примірників. Що стосується лише одного абонента, це класу коштує більше зусиль і гнучкості для класу, щоб надійно застосувати єдиність, ніж це робити, щоб абонент просто зберігав посилання і повторно використовував його.
cHao

69

Однотонний візерунок сам по собі не є проблемою. Проблема полягає в тому, що модель часто використовується людьми, що розробляють програмне забезпечення з об'єктно-орієнтованими інструментами, не маючи чіткого розуміння концепцій ОО. Коли одинакові вводяться в цьому контексті, вони, як правило, переростають в некеровані класи, які містять допоміжні методи для кожного невеликого використання.

Однотонні також є проблемою з точки зору тестування. Вони, як правило, ускладнюють написання ізольованих одиничних тестів. Інверсія управління (IoC) та ін'єкція залежності є моделями, призначеними для подолання цієї проблеми об'єктно-орієнтованим способом, який піддається одиничному тестуванню.

У середовищі, зібраному зі сміттям, одиночні кнопки можуть швидко стати проблемою щодо управління пам'яттю.

Існує також багатопотоковий сценарій, коли одиночні кнопки можуть стати вузьким місцем, а також проблема синхронізації.


4
я знаю, це багаторічна нитка. привіт @Kimoz u сказала: - одиночні кнопки можуть швидко стати проблемою щодо управління пам'яттю. хотіли б пояснити більш детально, яка проблема може виникнути стосовно одноразового та вивезення сміття.
Томас

@Kimoz. Питання задається "Чому однотонний шаблон сам по собі не є проблемою?" і ви просто повторили точку, але не надали навіть жодного дійсного випадку використання схеми сингтона.
Pacerier

@Thomas, тому що синглтон за визначенням існує лише в одному екземплярі. Отже, часто буває складно присвоїти єдине посилання нулю. Це можна зробити, але це означає, що ви повністю контролюєте точку, після якої синглтон не використовується у вашому додатку. І це рідко, і зазвичай зовсім протилежне тому, що шукають ентузіасти-одиночки: простий спосіб зробити єдиний екземпляр завжди доступним. У деяких DI-обрамах, таких як Guice або Dagger, неможливо позбутися сингла, і він назавжди залишається в пам'яті. (Хоча контейнери за умови одинаків набагато кращі, ніж домашні).
Snicolas

54

Синглтон реалізується за допомогою статичного методу. Статистичні методи уникають людям, які проводять тестування, оскільки їх не можна глузувати чи заглушувати. Більшість людей на цьому сайті є великими прихильниками тестування одиниць. Загальноприйнятою умовою для їх уникнення є використання інверсії схеми управління .


9
Це звучить скоріше як проблема з тестуванням одиниць, які можуть перевірити об'єкти (одиниці), функції (одиниці), цілі бібліотеки (одиниці), але не можуть стати статичними у класі (також одиницями).
v010дя

2
ви не гадаєте, все-таки змокціонувати всі зовнішні посилання? Якщо ви є, то яка проблема в moc одиночному, якщо ні, ви справді робите тестування?
Даїній

@Dainius: Знущання над екземплярами набагато менше проблем, ніж знущання над класами. Ви можете витягнути тестований клас з решти програми та протестувати з підробленим Singletonкласом. Однак це надзвичайно ускладнює процес тестування. По-перше, тепер вам потрібно мати можливість розвантажувати заняття за власним бажанням (що насправді не є варіантом для більшості мов) або запускати новий VM для кожного тесту (читайте: тести можуть зайняти тисячі разів довше). Однак для двох, залежність від Singleton- це деталізація щодо впровадження, яка зараз протікає у ваших тестах.
cHao

Powermock може глузувати з статичних речей.
Snicolas

чи знущання над об’єктом означає створення реального об’єкта? Якщо глузування не створює реального об'єкта, то чому це важливо, чи є клас однотонним чи метод статичним?
Арун Раай

45

Сінглтон також поганий, якщо мова йде про кластеризацію . Тому що тоді у вас більше немає «рівно одного сингтона» у вашій заяві.

Розглянемо таку ситуацію: Як розробник, ви повинні створити веб-додаток, який має доступ до бази даних. Щоб одночасні виклики бази даних не конфліктували між собою, ви створюєте збереження потоку SingletonDao:

public class SingletonDao {
    // songleton's static variable and getInstance() method etc. omitted
    public void writeXYZ(...){
        synchronized(...){
            // some database writing operations...
        }
    }
}

Отже, ви впевнені, що у вашій програмі існує лише один сингтон, і вся база даних проходить цю єдину SingletonDao. Зараз ваше виробниче середовище виглядає приблизно так: Одномісний одномісний

На сьогодні все добре.

Тепер, подумайте, що ви хочете налаштувати декілька примірників вашого веб-програми в кластері. Тепер у вас раптом щось таке:

Багато одинаків

Це звучить дивно, але зараз у вашому додатку багато одинаків . І саме так не повинно бути одиночний: Маючи багато предметів. Це особливо погано, якщо ви, як показано в цьому прикладі, хочете здійснювати синхронізовані дзвінки до бази даних.

Звичайно, це приклад поганого використання сингла. Але повідомлення цього прикладу: Ви не можете розраховувати на те, що у вашому додатку є рівно один екземпляр сингтона, особливо якщо мова йде про кластеризацію.


4
якщо ви не знаєте, як реалізувати одиночне, ви не повинні цього робити. Якщо ви не знаєте, чим займаєтесь, вам слід це знайти спочатку, і лише після цього робити те, що вам потрібно.
Даїній

3
Це цікаво, у мене питання. Тож у чому саме проблема, якщо одиночні кнопки - кожен на іншій машині / JVM - підключаються до єдиної бази даних? Область дії Singletons є лише для цього конкретного JVM, і це все ще актуально навіть у кластері. Замість того, щоб просто сказати по-філософськи, що ця конкретна ситуація погана, оскільки наш намір був єдиним об'єктом у всьому застосуванні, я був би радий побачити будь-які технічні проблеми, які можуть виникнути через цю домовленість.
Saurabh Patil

39
  1. Він легко (ab) використовується як глобальна змінна.
  2. Класи, які залежать від синглів, порівняно складніше одиничного тестування ізольовано.

33

Монополія - ​​це диявол, а одиночні особи з нечитаним / незмінним станом є "справжньою" проблемою ...

Прочитавши Синглтони - патологічні брехуни, як це запропоновано у відповіді Джейсона, я натрапив на цей маленький примх, який дає найкращий представлений приклад того, як одинаків часто зловживають.

Глобальний - це погано, оскільки:

  • а. Це викликає конфлікт у просторі імен
  • б. Це викриває державу необґрунтовано

Якщо мова йде про Сінглтон

  • а. Явний вихідний спосіб викликати їх, запобігає конфліктам, тому вкажіть a. це не проблема
  • б. Однотонні без штату є (як фабрики) - це не проблема. Синглтони зі станом можуть знову потрапляти у дві категорії, ті, які є незмінними або записуються один раз і читаються багато (файли конфігурацій / властивостей). Це непогано. Змінні одинарники, які є власниками довідок, - це ті, про які ви говорите.

В останньому твердженні він посилається на концепцію блогу "одинаки - брехуни".

Як це стосується монополії?

Щоб розпочати гру монополії, спочатку:

  • ми спочатку встановлюємо правила, щоб усі були на одній сторінці
  • всім дається рівний старт на початку гри
  • подано лише один набір правил, щоб уникнути плутанини
  • правила заборонено змінювати протягом усієї гри

Тепер для тих, хто насправді не грав монополію, ці стандарти ідеальні в кращому випадку. Поразку в монополії важко проковтнути, тому що монополія - ​​це гроші, якщо ви програєте, вам потрібно старанно спостерігати за рештою гравців, які закінчують гру, а втрати, як правило, стрімкі та грізні. Отже, правила, як правило, вивертаються в якийсь момент, щоб слугувати інтересам одних гравців за рахунок інших.

Отже, ви граєте в монополію з друзями Бобом, Джо та Едом. Ви швидко будуєте свою імперію і споживаєте частку ринку з експоненціальною швидкістю. Ваші опоненти слабшають, і ви починаєте пахнути кров’ю (образно). Ваш приятель Боб вклав усі свої гроші на блокування мереж якнайбільше властивостей малої вартості, але він не отримує високої віддачі від інвестицій так, як він очікував. Боб, як удача від удачі, приземляється на ваш Boardwalk і вирізаний з гри.

Тепер гра переходить від доброзичливого кочення до серйозного бізнесу. Боб був прикладом невдачі, і Джо і Ед не хочуть закінчуватися як "той хлопець". Отже, ставши провідним гравцем, ви раптом стаєте ворогом. Джо і Ед починають займатися за столом, за грошовими введеннями грошей, недооціненою заміною будинків і взагалі будь-чим, щоб послабити вас як гравця, поки один з них не підніметься на вершину.

Тоді, замість того, щоб один з них виграв, процес починається все спочатку. Раптом, кінцевий набір правил стає рухомою ціллю, і гра перероджується у тип соціальних взаємодій, який би став основою кожного рейтингового реаліті-шоу з високим рейтингом після Survivor. Чому, тому що правила змінюються і немає єдиної думки щодо того, як / чому / що вони повинні представляти, і що ще важливіше, ніхто не приймає рішення. У цей момент кожен гравець в грі створює свої власні правила і настає хаос, поки двоє з гравців не надто втомилися, щоб не відставати від шараду і повільно здаватися.

Отже, якби правило з гри в точній формі представляло синглтон, правилом монополії був би приклад зловживань.

Як це стосується програмування?

Окрім усіх очевидних проблем безпеки та синхронізації, що існують із змінними синглтонами ... Якщо у вас є один набір даних, який може читатись / маніпулювати кількома різними джерелами одночасно та існує протягом життя програми, це, мабуть, вдалий час відступити і запитати «чи я тут використовую правильний тип структури даних».

Особисто я бачив, як програміст зловживає синглом, використовуючи його як якесь скручене сховище баз даних між програмами. Попрацювавши над кодом безпосередньо, я можу засвідчити, що це було повільним (через всі замки потоку, необхідними для забезпечення його потокової безпеки) і кошмаром для роботи (через непередбачуваний / переривчастий характер помилок синхронізації), і майже неможливо перевірити в умовах "виробництва". Звичайно, система могла бути розроблена за допомогою опитування / сигналізації для подолання деяких проблем продуктивності, але це не вирішило б проблеми з тестуванням, і чому б не турбуватися, коли «справжня» база даних вже може виконати таку ж функціональність у набагато більш надійній / масштабований спосіб.

Сінглтон - це лише варіант, якщо вам потрібно те, що надає синглтон. Екземпляр об'єкта лише для читання. Це ж правило має також каскадувати до властивостей / членів об'єкта.


1
Що робити, якщо одиночний обробляє гроші?
Йола

@Yola Це зменшило б кількість записів, якщо одиночне планується оновити за заздалегідь визначеним та / або фіксованим графіком, тим самим зменшуючи розбіжність потоків. Тим не менш, ви не зможете точно перевірити будь-який з кодів, що взаємодіють з однотонним, якщо ви не знущаєтесь над немедлентовим екземпляром, який імітує те саме використання. Люди TDD, мабуть, мали б пристосування, але це спрацювало б.
Еван Плейс

@EvanPlaice: Навіть із макетом у вас виникнуть проблеми з кодом, який говорить Singleton.getInstance(). Мова, яка підтримує рефлексію, могла б обійти її, встановивши поле, де зберігається Єдиний справжній екземпляр. ІМО, однак, тести стають трохи менш надійними, коли ви взялися за маніпулювання навколо приватного стану іншого класу.
cHao

28

Сінглтон - це не про один екземпляр!

На відміну від інших відповідей, я не хочу говорити про те, що не так з Singletons, але щоб показати вам, наскільки вони потужні та приголомшливі при правильному використанні!

  • Проблема : Singleton може стати проблемою в багатопотоковому середовищі.
    Рішення : Використовуйте процес одноразового завантаження для ініціалізації всіх залежностей вашого одиночного.
  • Проблема : важко знущатися з одинаків.
    Рішення : Використовуйте заводський зразок методу для глузування

Ви можете нанести MyModelна карту TestMyModelклас, який успадковує його, і скрізь, коли MyModelбуде TestMyModelзроблено ін'єкцію, ви отримаєте вкладення. - Проблема : одиночні кнопки можуть спричинити витік пам'яті, оскільки вони ніколи не утилізуються.
Рішення : Ну, розпоряджайтесь ними! Реалізуйте зворотний дзвінок у вашій програмі, щоб правильно розпоряджатися одиночними кнопками, ви повинні видалити всі пов’язані з ними дані та, нарешті, видалити їх із Заводу.

Як я вже зазначив у заголовку синглтон - це не про один екземпляр.

  • Singletons покращує читабельність : Ви можете подивитися на свій клас і побачити, який сингтон вводили, щоб зрозуміти, що це за залежності.
  • Singletons покращує технічне обслуговування : Після того, як ви видалили залежність із класу, ви щойно видалили інженентну інженерію , вам не потрібно йти та редагувати велику посилання інших класів, які щойно перемістили вашу залежність (Це для мене смердючий код @Jim Burger )
  • Singletons покращує пам’ять та продуктивність . Коли у вашій програмі відбувається щось, і для цього потрібен довгий ланцюжок зворотних викликів, ви витрачаєте пам’ять та продуктивність, використовуючи Singleton, ви скорочуєте середнього чоловіка та покращуєте продуктивність та використання пам'яті ( уникаючи зайвих локальних змінних змінних).

2
Це не стосується моєї основної проблеми з Singletons, це те, що вони дозволяють отримати доступ до глобального стану з будь-якого з тисяч класів у вашому проекті.
LegendLength

8
Це була б мета ...
Ілля Газман

LegendLength Чому це неправильно? Наприклад, у своїй програмі у мене є однотонний Settingsоб’єкт, який доступний з будь-якого віджета, щоб кожен віджет знав про те, як форматувати відображені числа. Якби це не був глобально доступний об'єкт, я повинен був би ввести його в конструктор до кожного віджета в конструкторі і зберегти посилання на нього як змінну члена. Це жахлива трата пам’яті та часу.
ВК

23

Моя відповідь про те, наскільки синглтони погані - це завжди, "важко зробити правильно". Багато основоположних компонентів мов є однотонними (класи, функції, простори імен і навіть оператори), як і компоненти в інших аспектах обчислень (localhost, маршрут за замовчуванням, віртуальна файлова система тощо), і це не випадково. Хоча вони час від часу викликають неприємності та розчарування, вони також можуть змусити багато чого працювати на багато.

Дві найбільші викрутки, які я бачу, це: трактувати це як глобальне & не в змозі визначити закриття Singleton.

Усі говорять про Сінглтона як про глобальних, тому що вони в основному є. Однак багато (на жаль, не всі) негараздів у глобальному масштабі пов'язані не з глобальністю, а з тим, як ви цим користуєтеся. Те саме стосується і одиночних. Насправді тим більше, що "одиничний екземпляр" насправді не повинен означати "глобально доступний". Це скоріше природний побічний продукт, і враховуючи все погане, що, як ми знаємо, випливає з цього, ми не повинні поспішати з використанням глобальної доступності. Як тільки програмісти бачать Singleton, вони, здається, завжди отримують доступ до нього безпосередньо через його метод екземпляра. Натомість ви повинні перейти до нього так само, як і будь-який інший об’єкт. Більшість кодів навіть не повинні знати, що він має справу з Singleton (вільне з'єднання, правда?). Якщо лише невеликий шматочок коду отримує доступ до об'єкта, такого як він є глобальним, багато шкоди не скасовується.

Контекст Сінглтона також дуже важливий. Визначальною характеристикою Сінглтона є те, що існує "лише один", але правда полягає в тому, що він "лише один" в якомусь контексті / просторі імен. Зазвичай вони є однією з: одна на нитку, процес, IP-адресу або кластер, але також може бути одна на процесор, машину, простір імен мови / завантажувач класів / що завгодно, підмережа, Інтернет тощо.

Інша, менш поширена помилка - ігнорування способу життя Singleton. Тільки тому, що є лише один, не означає, що Сінглтон є всемогутнім "завжди був і завжди буде", а також це взагалі бажано (об'єкти без початку і кінця порушують усілякі корисні припущення в коді, і їх слід використовувати лише за найвідчайдушніших обставин.

Якщо ви уникнете цих помилок, Singletons все ще може бути PITA, але він готовий бачити, що багато найгірших проблем значно полегшуються. Уявіть Java Singleton, який чітко визначається як один раз для завантажувача класів (це означає, що йому потрібна політика безпеки потоку), з визначеними методами створення та знищення та життєвим циклом, який диктує, коли і як вони будуть викликатися, і чий "екземпляр" метод має захист пакунків, тому до нього, як правило, доступ здійснюється через інші, не глобальні об'єкти. Все-таки потенційне джерело неприємностей, але, безумовно, набагато менше проблем.

На жаль, замість того, щоб викладати хороші приклади того, як робити синглтон. Ми викладаємо погані приклади, нехай програмісти тікають, використовуючи їх на деякий час, а потім скажемо їм, що вони є поганою схемою дизайну.


23

Дивіться Вікіпедію Singleton_pattern

Деякі люди, які вважають, що вона надмірно використана, її вважають анти-зразком, вводячи зайві обмеження в ситуаціях, коли фактично не потрібен єдиний екземпляр класу. [1] [2] [3] [4]

Посилання (лише відповідні посилання зі статті)

  1. ^ Алекс Міллер. Шаблони, які я ненавиджу №1: Сінглтон , липень 2007 року
  2. ^ Скотт Денсмор. Чому одинаки злі , травень 2004 року
  3. ^ Стів Єгге. Сінглтон вважався дурним , вересень 2004 року
  4. ^ JB Rainsberger, IBM. Розумно використовуйте одинаків , липень 2001 року

8
Опис цього шаблону не пояснює, чому його вважають злим ...
Jrgns,

2
Навряд чи справедливо: "Деякі люди, які вважають, що він надмірно використовується, також вважають анти-зразком, вводячи зайві обмеження в ситуаціях, коли єдиний екземпляр класу насправді не потрібен". Подивіться на посилання ... У будь-якому випадку є RTFM для мене.
GUI Junkie

17

Справа не в тому, що самі одинаки погані, але схема дизайну GoF є. Єдиний справді аргумент, що є дійсним - це те, що модель дизайну GoF не піддається тестуванню, особливо якщо тести виконуються паралельно.

Використання одного примірника класу є дійсною конструкцією, якщо ви застосовуєте в коді такі засоби:

  1. Переконайтеся, що клас, який буде використовуватися як одиночний, реалізує інтерфейс. Це дозволяє запускати заглушки або макети за допомогою одного інтерфейсу

  2. Переконайтесь, що Singleton захищений від потоку. Це дано.

  3. Сингл має бути простим за своєю суттю і не надто складним.

  4. Під час виконання вашої програми, коли одиночні кнопки потрібно передати певному об'єкту, використовуйте фабрику класів, яка будує цей об’єкт і фабрика класів передає екземпляр singleton до класу, який йому потрібен.

  5. Під час тестування та для забезпечення детермінованої поведінки створіть клас однотонних як окремий екземпляр, як власне сам клас, чи заглушку / макет, що реалізує свою поведінку, та передайте її як до класу, який цього вимагає. Не використовуйте фактор класу, який створює тестований об'єкт, який потребує синглтона під час тестування, оскільки він передасть єдиний глобальний примірник його, що перемагає мету.

Ми використовували Singletons у своїх рішеннях з великим успіхом, які можна перевірити, забезпечуючи детерміновану поведінку в паралельних потоках тестового запуску.


+1, нарешті відповідь, яка стосується, коли сингл може бути дійсним.
Pacerier

16

Я хотів би сказати 4 пункти у прийнятій відповіді, сподіваюся, хтось може пояснити, чому я помиляюся.

  1. Чому приховування залежностей у вашому коді погано? Уже є десятки прихованих залежностей (виклики C виконання часу, виклики API OS, дзвінки глобальних функцій), а однотонні залежності легко знайти (пошук наприклад ()).

    "Зробити щось глобальне, щоб уникнути його передачі - кодовий запах." Чому б не пропустити щось навколо, щоб не перетворити його на запах коду?

    Якщо ви передаєте об'єкт через 10 функцій у стеку дзвінків, щоб уникнути синглтона, це так чудово?

  2. Принцип єдиної відповідальності: Я думаю, це трохи розпливчасто і залежить від вашого визначення відповідальності. Відповідне питання було б, чому додавання цієї специфічної "відповідальності" до класу має значення?

  3. Чому передача об'єкта класу робить його більш щільно з'єднаним, ніж використання цього об'єкта як синглтона зсередини класу?

  4. Чому це змінюється, як довго триває держава? Однотонні можна створити або знищити вручну, тому управління все ще є, і ви можете зробити життя таким же, як і життя немедлентового об'єкта.

Щодо одиничних тестів:

  • не всі класи потребують тестування одиниць
  • Не всі класи, які потребують тестування одиниць, повинні змінити реалізацію синглтона
  • якщо вони роблять потрібно бути протестовано і зробити необхідність змінити реалізацію, це легко змінити клас за допомогою Сінглтона до мати одноплодной передану їй через ін'єкцію залежностей.

1
1. Усі ці приховані залежності? Вони теж погані. Приховані залежності - це завжди зло. Але що стосується CRT та OS, вони вже є, і це єдиний спосіб зробити щось. (Спробуйте написати програму C, не використовуючи час виконання або ОС.) Ця здатність робити речі значно переважає їх негативи. Сінглтони в нашому коді не отримують такої розкоші; оскільки вони знаходяться в нашій сфері контролю та відповідальності, кожне використання (читайте: кожна додаткова прихована залежність) має бути виправданим як єдиний розумний спосіб зробити роботу. Дуже, дуже мало їх є насправді.
cHao

2. "Відповідальність" зазвичай визначається як "причина зміни". Сінгтон закінчується як керуючи своїм життям, так і виконуючи свою справжню роботу. Якщо ви змінюєте, як виконується завдання або будується графік об'єкта, вам доведеться змінити клас. Але якщо у вас є інший код побудови об’єктного графіка, і ваш клас просто виконує свою справжню роботу, цей код ініціалізації може встановлювати об'єктний графік, як би це не подобалося. Все набагато модульніше і перевіряється, тому що ви можете вставити тестові подвійні елементи і зірвати все за бажанням, і ви більше не покладаєтесь на приховані рухомі частини.
cHao

1
@cHao: 1. Добре, що ти визнаєш, що "вміння робити речі значно перевершує їх негативи". Прикладом може слугувати рамка ведення журналу. Зло мандат передавати глобальний об'єкт реєстрації шляхом введення залежності через шари викликів функцій, якщо це означає, що розробники не рекомендують вести журнал. Значить, одиночний. 3. Ваша щільна точка з'єднання є актуальною лише в тому випадку, якщо ви хочете, щоб клієнти класу контролювали поведінку за допомогою поліморфізму. Це часто не так.
Джон

2
4. Я не впевнений, що "не можна знищити вручну", це логічний підсумок "може бути лише один екземпляр". Якщо саме так ви визначаєте одиночку, ми не говоримо про те саме. Усі класи не повинні проходити перевірку. Це ділове рішення, а іноді вартість продажу на ринку чи розвиток буде мати перевагу.
Джон

1
3. Якщо ви не хочете поліморфізму, то вам навіть екземпляр не потрібен. Ви також можете зробити його статичним класом, тому що ви все одно прив'язуєте себе до одного об'єкта та єдиної реалізації - і, принаймні, API не бреше вам стільки.
cHao

15

Вінс Хастон має такі критерії, які мені здаються розумними:

Синглтон слід розглядати лише в тому випадку, якщо всі три наступні критерії задоволені:

  • Право власності на один екземпляр не може бути розумно присвоєний
  • Бажана лінива ініціалізація
  • Глобальний доступ не передбачений інакше

Якщо право власності на один екземпляр, коли і як відбувається ініціалізація, і глобальний доступ не є проблемами, Singleton не є достатньо цікавим.


14

Синглтони погані з пуристської точки зору.

З пратичної точки зору, синглтон є компромісним часом, що розвивається, та складністю .

Якщо ви знаєте, що ваша заявка не зміниться так сильно, вони досить добре йти. Просто знайте, що вам може знадобитися переробляти речі, якщо ваші вимоги будуть змінюватися несподівано (що в більшості випадків є цілком нормальним).

Одноразові інколи також ускладнюють тестування одиниць .


3
Мій досвід полягає в тому, що починати з одинаків дійсно зашкодить тобі навіть у короткостроковій перспективі, не рахуючи довгострокової роботи. Цей ефект міг би бути меншим, якщо програма вже існує деякий час, і, ймовірно, вже заражена іншими одиночними кнопками. Починаючи з нуля? Уникайте їх за будь-яку ціну! Хочете одного екземпляра об’єкта? Нехай фабрика керує інстанцією цього об'єкта.
Свен

1
AFAIK Singleton - заводський метод. Тому я не отримую вашої рекомендації.
tacone

3
"Фабрика"! = "Фабричний_метод, який не можна відокремити від інших корисних речей того ж класу"
Свен,

13

З закономірністю немає нічого поганого, якщо припустити, що він використовується для певного аспекту вашої моделі, який є справді єдиним.

Я вважаю, що люфт відбувається через його надмірне використання, яке, в свою чергу, пов'язане з тим, що це найпростіший шаблон для розуміння та реалізації.


6
Я думаю, що люфт має більше спільного з людьми, які практикують формалізоване тестування, розуміючи, що вони є кошмаром для боротьби.
Джим Бергер

1
Не впевнений, чому це на рівні -1. Це не сама описова відповідь, але він також не помиляється.
Програматор поза законом

13

Я не збираюся коментувати аргументи доброго / злого, але я не користувався ними з моменту приходу Весни . Використання ін'єкційних залежностей значною мірою усунуло мої вимоги щодо одиночних, службових перекладачів та заводів. Я вважаю це набагато більш продуктивним та чистим середовищем, принаймні для роботи, яку я роблю (веб-додатки на базі Java).


3
Чи не весняні боби, за замовчуванням, одиночні?
стрункий

3
Так, але я маю на увазі "кодування" синглів. Я не написав синглтона (тобто з приватним конструктором yada yada yada відповідно до шаблону дизайну) - але так, з весни я використовую один екземпляр.
пруль

4
тож коли інші це роблять, це нормально (якщо я буду використовувати це після), але якщо інші це робитимуть, а я не буду ним користуватися, це зло?
Даїній

11

Синглтон є зразком і його можна використовувати або зловживати так само, як і будь-який інший інструмент.

Погана частина сингтона - це звичайно користувач (або, якщо я сказати, неналежне використання синглтона для речей, які він не призначений робити). Найбільший злочинець використовує синглтон як підроблену глобальну змінну.


1
Дякую Локі :) Точно моя думка. Весь полювання на відьом нагадує мені про дискусію в гото. Інструменти призначені для людей, які вміють ними користуватися; використання інструменту, який вам не подобається, може бути небезпечним для вас, тому уникайте цього, але НЕ кажіть іншим не користуватися / не вчитися правильно ним користуватися. Я не зовсім "одноосібник", але мені подобається те, що у мене є такий інструмент, і я можу відчути, де це доречно використовувати. Період.
dkellner

8

Коли ви пишете код за допомогою одиночних клавіш, скажімо, реєстратора або підключення до бази даних, а потім виявите, що вам потрібно більше одного журналу або більше однієї бази даних, ви потрапили в біду.

Однотонам дуже важко переходити від них до звичайних об'єктів.

Крім того, написати занадто легко, що не є безпечним для потоків синглів.

Замість того, щоб використовувати одиночні кнопки, вам слід передати всі необхідні об'єкти утиліти від функції до функції. Це можна спростити, якщо ви загорнете їх у помічний об’єкт, як-от так:

void some_class::some_function(parameters, service_provider& srv)
{
    srv.get<error_logger>().log("Hi there!");
    this->another_function(some_other_parameters, srv);
}

4
аргумент для кожного методу є геніальним, він повинен розглянути принаймні 10 найкращих способів, як забруднювати свій пасік.
Даїній

Це очевидний недолік, і той, з яким повинна була працювати мова, за допомогою аргументів, які якимось чином поширюються на вкладені виклики, але відсутня така підтримка, це потрібно робити вручну. Врахуйте, що навіть природні одинаки, як предмет, що представляє системний годинник, можуть мати проблеми. Наприклад, як ви збираєтесь прикрити залежний від годинника код (подумайте, кілька тарифного лічильника електроенергії) тестами?
Роман Одайський

залежить, що ви тестуєте, якщо ви не тестуєте синглтон, чому вам все одно, як він поводиться, якщо ваш 2 віддалений об’єкт залежить від поведінки один одного, це не проблема одиночки ..
Дайніус

Не могли б ви вказати, яка мова поширюватиметься на вкладені дзвінки?
Дайній

1
Якщо у вас є один модуль, який залежить від іншого, і ви не знаєте / не можете його зробити, вам буде важко, незалежно від того, синглтон чи ні. Люди використовують спосіб успадкування часто там, де їм слід використовувати склад, але ви не кажете, що спадщина погана, і OOP слід уникати будь-якою ціною, тому що так багато людей там роблять помилки дизайну, чи ви?
Дайній

8

Проблеми з одиночними проблемами - це питання збільшення обсягу, а отже, і зв'язку . Не можна заперечувати, що існують деякі ситуації, коли вам потрібен доступ до одного екземпляра, і це може бути здійснено іншими способами.

Зараз я вважаю за краще конструювати навколо контейнера інверсії керування (IoC) і дозволяю контейнеру керувати життям. Це дає вам перевагу класам, які залежать від екземпляра, не знати про те, що існує один екземпляр. Тривалість життя сингла може бути змінена в майбутньому. Одного разу з таким прикладом, з яким я стикався нещодавно, було легке налаштування від однопотокової до багатопотокової.

FWIW, якщо це PIA, коли ви намагаєтеся перевірити його, тоді він переходить до PIA, коли ви намагаєтеся налагодити, виправити помилку або покращити його.



7

Синглтони НЕ погані. Це тільки погано, коли ти робиш щось глобально унікальне, що не є глобально унікальним.

Однак існують "служби прикладних програм" (подумайте про систему обміну повідомленнями, яка змушує взаємодіяти компоненти) - це CALLS для одиночного класу, "MessageQueue" - клас, який має метод "SendMessage (...)".

Потім ви можете зробити наступне з усього місця:

MessageQueue.Current.SendMessage (новий MailArrivedMessage (...));

І, звичайно, робіть:

MessageQueue.Current.RegisterReceiver (це);

в класах, які реалізують IMessageReceiver.


6
І якщо я хочу створити другу чергу чергових повідомлень з меншим обсягом, чому я не можу дозволити повторно використовувати ваш код для його створення? Однотонний перешкоджає цьому. Але якщо ви просто створили звичайний клас черги повідомлень, а потім створили один глобальний екземпляр, щоб він виступав як "область застосування", я міг би створити другий екземпляр для іншого використання. Але якщо ви зробите клас одинарним, мені доведеться написати другий клас черги повідомлень.
jalf

1
Крім того, чому ми не повинні просто мати глобальний CustomerOrderList, щоб ми могли його добре називати з будь-якого місця, як MessageQueue? Я вважаю, що відповідь однакова для обох: це ефективно зробити глобальну змінну.
ЛегендаЛенгт

7

Занадто багато людей ставлять предмети, які не є безпечними для ниток у однотонному малюнку. Я бачив приклади DataContext ( LINQ to SQL ), виконані в однотонному шаблоні, незважаючи на те, що DataContext не є безпечним для потоків і є об'єктом одиничної роботи.


багато людей пишуть небезпечний багатопотоковий код, це означає, що нам слід усунути нитки?
Даїній

@Dainius: Насправді так. ІМО модель сумісності за замовчуванням повинна бути багатопроцесовою, з можливістю двох процесів (1) легко передавати повідомлення один одному та / або (2) обмінюватися пам'яттю за потребою. Нитка корисна, якщо ви хочете поділитися всім , але ви ніколи цього не хочете. Це можна було б наслідувати загальним адресним простором, але це також вважатиметься антидіаграмою.
cHao

@Dainius: І звичайно, це припускаючи, що паралельність чесного доброго взагалі потрібна. Часто все, що вам потрібно, - це вміти робити одне, поки ви чекаєте, коли ОС зробить щось інше. (Оновлення, наприклад, інтерфейсу користувача при зчитуванні з сокета, наприклад.) Пристойний API асинхронізації може зробити непотрібне в повному обсязі в величезній більшості випадків.
cHao

тож якщо у вас є величезна матриця даних, вам потрібен процес, краще це зробити в один потік, тому що багатьом людям це може зробити неправильно ..
Дайній

@Dainius: У багатьох випадках так. (Threading може насправді сповільнити вас , якщо ви додасте синхронізацію в суміш. Це прекрасний приклад того, чому багатопотокове читання не повинно бути першою думкою більшості людей.) В інших випадках краще було б мати два процеси, які поділяються просто потрібні речі. Звичайно, вам доведеться організувати обмін пам'яттю процесами. Але, чесно кажучи, я бачу, що це добре - принаймні, набагато краще, ніж дефолт у режимі загального користування. Він вимагає від вас чітко сказати (і так, в ідеалі, знати), які деталі мають спільний доступ, і таким чином, які частини потрібно захищати від потоку.
cHao

6

Ось ще одна річ про синглів, про які ще ніхто не сказав.

У більшості випадків "однотонність" - це деталізація реалізації для якогось класу, а не характеристика його інтерфейсу. Інверсія контейнера управління може приховувати цю характеристику від користувачів класу; вам просто потрібно позначити свій клас як одиночний (наприклад, з @Singletonанотацією на Java), і все; IoCC зробить все інше. Вам не потрібно надавати глобальний доступ до вашої одиночної інстанції, оскільки цим доступом вже керує IoCC. Таким чином, з IoC Singletons немає нічого поганого.

Голонг-синглтони, протилежні IoC Singletons, повинні викрити "однотонність" в інтерфейсі методом getInstance (), і вони страждають від усього сказаного вище.


3
На мою думку, "однотонність" - це деталь середовища середовища виконання, і його не слід розглядати програмісту, який написав код класу. Швидше, це питання, яке має враховувати клас USER. тільки КОРИСТУВАЧ знає, скільки справді потрібних екземплярів.
Земляний двигун

5

Синглтони не є злими, якщо ви використовуєте їх правильно і мінімально . Існує безліч інших хороших моделей дизайну, які замінюють потреби сингтона в якийсь момент (& також дає найкращі результати). Але деякі програмісти не знають про ті добрі зразки, і він використовує сингл у всіх випадках, що робить для них одиночне зло.


Дивовижно! Повністю згоден! Але ви могли б, і, можливо, повинні розробити значно більше. Наприклад, розширення моделей дизайну, які найчастіше ігноруються, і як "правильно і мінімально" використовувати одиночні кнопки. Легше сказати, ніж зробити ! : P
Крегокс

В основному альтернативою є передача об'єктів навколо за допомогою параметрів методу, а не доступ до них через глобальний стан.
LegendLength

5

По-перше, клас та його співробітники повинні спочатку виконувати намічене призначення, а не зосереджуватися на залежних. Управління життєвим циклом (коли створюються екземпляри та коли вони виходять за межі сфери застосування) не повинно бути частиною відповідальності класів. Найкращою практикою для цього є створення або налаштування нового компонента для управління залежностями за допомогою введення залежності.

Часто програмне забезпечення стає складнішим, є сенс мати кілька незалежних екземплярів класу Singleton з різним станом. Здійснення коду для простого захоплення сингтона в таких випадках неправильно. Singleton.getInstance()Для невеликих простих систем використання може бути нормальним, але воно не працює / масштабується, коли може знадобитися інший примірник того ж класу.

Жоден клас не слід розглядати як однотонний, але він повинен бути додатком його використання або як він використовується для налаштування залежних. Для швидкого і неприємного це не має значення - просто жорстке кодування, сказати, шляхи до файлів не має значення, але для більш великих застосувань такі залежності потрібно враховувати та керувати більш відповідним чином за допомогою DI.

Проблеми, які викликають одиночне тестування, є симптомом їх жорсткого кодування для одного випадку використання / середовища. Тестовий набір і безліч тестів - це кожен окремий і окремо щось, що не сумісне з жорстким кодуванням синглів.


4

Оскільки вони в основному є об'єктно-орієнтованими глобальними змінними, зазвичай ви можете проектувати свої класи таким чином, щоб вони вам не потрібні.


Якщо ви не обмежуєтесь одним екземпляром, вам знадобляться статичні члени у вашому класі, якими управляє семафори, що виходить майже однаково! Яка Ваша запропонована альтернатива?
Jeach

У мене величезна програма із "MainScreen", цей екран відкриває багато менших модальних / немодальних вікон / форм інтерфейсу користувача. IMHO Я вважаю, що MainScreen має бути однотонним, так що, наприклад, віджет десь у дальньому куті програми хоче показати свій статус у рядку стану MainScreen, все, що він повинен зробити, це MainScreen.getInstance (). SetStatus ( "Якийсь текст"); Що ви пропонуєте як альтернативу? Передати MainScreen у всьому додатку ?? : D
Салвін Френсіс

2
@SalvinFrancis: Що б я рекомендував, ви перестаєте мати об’єкти, які цікавляться речей, про які вони не повинні піклуватися, і прокрадаєтесь через додаток, щоб возитися один з одним. :) Ваш приклад набагато краще було б зробити з подіями. Якщо ви робите події правильно, віджет навіть не повинен дбати про те, чи є MainScreen взагалі; він просто транслює "ей, щось трапилось", і все, що підписалося на подію "речі трапилися" (будь то MainScreen, WidgetTest або щось інше цілком!), вирішує, як він хоче відповісти. Ось так і повинно робитись ООП у будь-якому випадку. :)
cHao

1
@Salvin Подумайте, як важко міркувати про MainScreen при налагодженні, якщо він "мовчки" оновлюється багатьма компонентами. Ваш приклад є ідеальною причиною, чому одиночні особи погані.
LegendLength
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.