Ответ
Чаще всего используется паттерн Singleton (Одиночка). Он обеспечивает создание единственного экземпляра класса и глобальную точку доступа к нему.
Применение: Управление общими ресурсами — конфигурация приложения, логгер, пул соединений с базой данных.
Пример реализации на Java:
public class DatabaseConnection {
private static DatabaseConnection instance;
private Connection connection;
private DatabaseConnection() {
// Приватный конструктор
}
public static synchronized DatabaseConnection getInstance() {
if (instance == null) {
instance = new DatabaseConnection();
}
return instance;
}
public Connection getConnection() {
return connection;
}
}
Ключевые аспекты и best practices:
- Потокобезопасность: Базовая реализация требует синхронизации (
synchronized). Более эффективные варианты:- Double-Checked Locking (с
volatile). - Статическая инициализация (
private static final Singleton instance = new Singleton();). - Enum Singleton (рекомендовано Джошуа Блохом).
- Double-Checked Locking (с
- Ленивая (Lazy) vs. Ранняя (Eager) инициализация: Singleton может создаваться при первом вызове
getInstance()(ленивая) или при загрузке класса (ранняя). - Проблемы: Усложняет модульное тестирование из-за глобального состояния и скрытых зависимостей.
- Современные альтернативы: Внедрение зависимостей (Dependency Injection, например, через Spring), где «одиночка» управляется контейнером IoC.
Ответ 18+ 🔞
А, слушай, вот эта ваша одиночка, блядь, Singleton! Ну классика же, ёпта, как этот Герасим с Муму — один на весь двор и всё, больше никого не пускают, блядь.
Ну то есть, представляешь: у тебя там конфиг приложения, логгер или, там, соединение с базой — и нахуя тебе десять таких объектов плодить? Один, сука, должен быть, как ядрёна вошь, один и точка! Чтобы все к нему ходили, как к пророку, и не пиздели ничего.
Вот смотри, как это на Java выглядит, только не засыпай сразу:
public class DatabaseConnection {
private static DatabaseConnection instance; // Вот он, сволочь одинокая, спрятан
private Connection connection;
private DatabaseConnection() { // Конструктор приватный! Чтобы всякие умники не могли просто так new DatabaseConnection() наклепать, блядь
// Тут инициализация, ну там подключение к базе и всё
}
public static synchronized DatabaseConnection getInstance() { // А вот единственные ворота, сука!
if (instance == null) { // Если ещё не создан, блядь...
instance = new DatabaseConnection(); // То вот, родим его
}
return instance; // А если уже есть — на, получай того же самого, не дёргайся
}
public Connection getConnection() {
return connection;
}
}
Вот и вся магия, казалось бы. Но нет, блядь! Тут же подводные ебучки-воробушки начинаются!
Во-первых, потоки, сука! Представь, два потока одновременно вломились в getInstance() и видят, что instance — null. Оба, блядь, решат его создать! И будет у тебя уже не один одиночка, а два уёбка-близнеца, и пошла пизда всему. Поэтому в примере выше стоит synchronized — это как турникет, блядь, по одному пропускает. Но это медленно, ёпта!
Умные дядьки поэтому придумали Double-Checked Locking, там с volatile — это чтобы и быстро, и безопасно. Или можно сразу создать его при загрузке класса — Eager Initialization. Типа private static final Singleton instance = new Singleton(); И всё, блядь, создался сразу и без всяких синхронизаций, хоть ты тресни.
А самый, блядь, крутой и правильный способ, который даже Джошуа Блох хвалит — это через Enum сделать. Это вообще красота, потому что он от рефлексии защищён и сериализация из коробки работает. Но это уже для гурманов, блядь.
Главная же проблема-то в чём? В том, что этот самый синглтон — он как глобальная переменная, замаскированная под класс. Тестировать это — пиздец! Он везде понатыкан, состояние общее, одна зависимость на весь проект. Чуть что — все тесты падают, как мухи, потому что один тест испоганил состояние, а второй уже на него опирается. Удивление пиздец!
Поэтому сейчас все модные ребята орут: «Нееет, блядь, нахуй синглтоны! Даёшь Dependency Injection!». Вот как в том же Spring: ты просто говоришь, что бин у тебя один (@Singleton scope), а контейнер сам, хитрая жопа, следит, чтобы он везде один и тот же инстанс подсовывал. И тестировать легче, и зависимости явные. Красота, блядь!
Но паттерн-то сам, он живучий, как манда с ушами. Пока есть задачи, где нужен один-единственный контроллер на всю систему, он будет жить. Так что знать его надо, но применять с оглядкой, а то охуеешь потом.