JavaRush /Java блог /Random UA /Паттерни та Singleton – для всіх, хто вперше з ними зіткн...
Автор
Александр Выпирайленко
Java-разработчик в Toshiba Global Commerce Solutions

Паттерни та Singleton – для всіх, хто вперше з ними зіткнувся

Стаття з групи Random UA
Ця стаття орієнтована на тих, хто вперше зіткнувся з поняттям патернів, почув про Singleton'e, або якимось чином його зробив, але так нічого й не зрозуміли. Welcome! Вперше з патернами студенти JavaRush стикаються на 15 рівні, коли несподіваним чином кеп просить "закріпити" і реалізувати патерн Singletonз лінивою реалізацією. У студентів, які вперше почули про Singleton, миттєво виникає купа питань: що взагалі таке патерн, навіщо він потрібен, який ще й нарешті Singleton, що ще за лінива реалізація. Почнемо відповідати по-порядку: Паттерни та Singleton – для всіх, хто вперше з ними зіткнувся.

Що взагалі таке патерн

Відповідати на це питання для кращого розуміння, гадаю, варто з історії. Серед програмістів є така знаменита четвірка авторів: Еріх Гамма, Річард Хелм, Ральф Джонсон та Джон Вліссідес, яким спала на думку цікава думка.
Паттерни та Singleton – для всіх, хто вперше з ними зіткнувся.
Вони помітабо, що з написанні програм їм часто доводиться вирішувати приблизно одні й самі завдання, і писати структурою однотипний код. Тому вони вирішабо описати як патернів типові шаблони, які часто доводиться використовувати в об'єктно-орієнтованому програмуванні. Книжка вийшла 1995 року під назвою «Прийоми об'єктно-орієнтованого проектування. Паттерни проектування» . Назва книги виявилася занадто довгою, і її просто почали називати «Книгою банди чотирьох» . У першому виданні було опубліковано 23 патерни, після чого було відкрито і десятки інших. Так от, відповідаючи на запитання цього параграфа, — «Що ж таке патерни» , підсумуємо буквально кількома словами:
Паттерн – це стандартизоване вирішення проблеми, що часто зустрічається.
І Singleton– це лише один з таких патернів.

Навіщо потрібні патерни (шаблони проектування)

Програмувати виходить і без знання патернів, переконатися в цьому можна просто усвідомивши той факт, що до 15 рівня на JavaRush ви написали сотні міні-програм, нічого не знаючи про їх існування. Це говорить про те, що патерн - це свого роду інструмент, наявність якого і відрізняє майстра від любителя:
Паттерни та Singleton – для всіх, хто вперше з ними зіткнувся - 3
У патернах описується, як правильно вирішувати одне з типових завдань. Як наслідок, знання патернів заощаджує ваш час. Можна навести аналогію з алгоритмами. Наприклад, можна вигадувати "свій" алгоритм сортування з блекджеком та цифрамиі витратити на це багато часу, а можна використовувати вже давно описаний та реалізувати його. Те саме і з патернами. Плюс до всього, з використанням патернів код стає більш стандартизованим, а при використанні потрібних шаблонів у вас буде менше ймовірності зробити помилки, оскільки їх уже давно передбачали та усунули у цьому патернті. Ну і плюс до всього, знання патернів дозволяє програмістам краще розуміти одне одного. Досить просто вимовити назву шаблону, замість того, щоб намагатися пояснити своїм колегам-програмістам, чого ви хочете від них. Отже, підсумуємо, шаблони проектування допомагають:
  • не винаходити велосипед, а використовувати стандартні рішення;
  • стандартизувати код;
  • стандартизувати термінологію;
Наприкінці цього розділу відзначимо, що всі різноманіття патернів можна спрощено розбити на три великі групи:
Паттерни та Singleton – для всіх, хто вперше з ними зіткнувся - 4

Нарешті патерн Singleton

Singletonвідноситься до породжувальних патернів . Його дослівний переклад – одинак. Цей патерн гарантує, що клас має лише один об'єкт (один екземпляр класу) і до цього об'єкта надається глобальна точка доступу. З опису має бути зрозуміло, що цей патерн повинен застосовуватись у двох випадках:
  1. коли у вашій програмі має бути створено не більше одного об'єкта будь-якого класу. Наприклад, у комп'ютерній грі у вас є клас «Персонаж», і цей клас повинен мати лише один об'єкт, що описує самого персонажа.

  2. коли потрібно надати глобальну точку доступу до об'єкта класу. Іншими словами, потрібно зробити так, щоб об'єкт викликався з будь-якого місця програми. І, на жаль, для цього не просто створити глобальну змінну, адже вона не захищена від запису і будь-хто може змінити значення цієї змінної і глобальна точка доступу до об'єкта буде втрачена. Це властивості Singleton'a потрібно, наприклад, коли у вас є об'єкт класу, який працює з базою даних, і вам потрібно, щоб до бази даних був доступ із різних частин програми. А Singletonгарантуватиме, що жодний інший код не замінив створений раніше екземпляр класу.
Ось ці дві задачі і вирішує Singleton: об'єкт у програмі має бути один і до нього є глобальний доступ. У прикладі на 15 рівні кеп просить реалізувати цей патерн для наступного завдання (ось її опис):
Паттерни та Singleton – для всіх, хто вперше з ними зіткнувся - 5
Уважно прочитавши умову, стає зрозуміло, навіщо тут потрібен саме Singleton(Одиночка). Адже в програмі просять створити по одному об'єкту кожного класу: Sun, Moon, Earth. І логічно припустити, що кожен клас у програмі повинен створювати не більше одного Сонця / Місяця / Землі, інакше це буде абсурд, якщо, звичайно, ви не пишите свою версію зоряних воїн. Особливість реалізації SingletonJava за три кроки Поведінка Одинаки Java неможливо реалізувати за допомогою звичайного конструктора, тому що конструктор завжди повертає новий об'єкт. Тому всі реалізаціїSingleton'a зводяться до того, щоб приховати конструктор і створити публічний статичний метод, який буде керувати існуванням об'єкта-одиначки і «знищувати» всіх об'єктів, що знову з'являються. У разі виклику Singleton'a він повинен створити новий об'єкт (якщо його ще немає в програмі), або повернути вже створений. І тому: #1. – Потрібно додати до класу приватне статичне поле, що містить одиночний об'єкт:
public class LazyInitializedSingleton {
	private static LazyInitializedSingleton instance; //#1
}
#2. - Зробити конструктор класу (конструктор за замовчуванням) приватним (щоб доступ до нього був закритий за межами класу, тоді він не зможе повертати нові об'єкти):
public class LazyInitializedSingleton {
	private static LazyInitializedSingleton instance;
private LazyInitializedSingleton(){} // #2
}
#3 . – Оголосити статичний метод, який буде використовуватися для отримання одинаки:
public class LazyInitializedSingleton {
    private static LazyInitializedSingleton instance;
        private LazyInitializedSingleton(){}
        public static LazyInitializedSingleton getInstance(){ // #3
        if(instance == null){		//якщо об'єкт ще створено
            instance = new LazyInitializedSingleton();	//створити новий об'єкт
        }
        return instance;		// Повернути раніше створений об'єкт
    }
}
Вищеописаний приклад дещо незграбний, адже ми просто приховуємо конструктор і надаємо замість стандартного конструктора свій метод. Так як ця стаття спрямована на те, щоб студенти JavaRush'a змогли вперше доторкнутися до цього патерна (і патернами в принципі), тут не будуть наведені особливості реалізації більш складних одинаків. Зазначимо лише, що залежно від складності програми може знадобитися докладніше доопрацювання цього патерну. Наприклад, у багатопотоковому середовищі (див. тему Thread'и), кілька різних потоків можуть одночасно викликати метод отримання Одинаки, і описаний вище код перестане працювати, бо кожен окремий потік зможе створити відразу кілька екземплярів класу. Тому є ще кілька різних підходів до створення правильних Thread-safe одинаків. Але це вже інша історія =) І на останок. Що ж таке Лінива Ініціалізація, про яку просив кеп Ледачу ініціалізацію (Lazy Initialization) ще називають відкладеною ініціалізацією. Це прийом у програмуванні, коли ресурсомістка операція (а створення об'єкта – це ресурсомістка операція) виконується на вимогу, а чи не заздалегідь. Що загалом і відбувається у нашому коді Singleton'a. Інакше кажучи, наш об'єкт створюється на момент звернення щодо нього, а чи не заздалегідь. Не слід вважати, що поняття лінивої ініціалізації якось жорстко пов'язане саме з ним Singleton. Відкладена ініціалізація також використовується і в інших патернах проектування, що породжують, наприклад в таких як Proxy (Заступник) і Factory Method (Фабричний метод), але це теж інша історія =) Під час підготовки матеріалів статті використовувалися такі источники:
  1. Java Singleton Design Pattern Best Practices with Examples
  2. Патерни проектування
  3. Правильний Singleton в Java
Коментарі (1)
ЩОБ ПОДИВИТИСЯ ВСІ КОМЕНТАРІ АБО ЗАЛИШИТИ КОМЕНТАР,
ПЕРЕЙДІТЬ В ПОВНУ ВЕРСІЮ
Sava_crosava Рівень 23
26 жовтня 2023
Закликаю робити актив під статтями українською мовою!!! Підозрюю що статті перекладаються в два кліка через перекладач( Але якщо це буде мати попит та відгук від української спільноти, таких статтей буде більше і скоро буде більше оригінальних статтей українською)🤟