1. Создание и уничтожение объектов: фабрики, синглтоны, зависимости
Создание и уничтожение объектов: фабрики, синглтоны, зависимости
Создание объектов в Java выглядит простым: вызвал new — получил экземпляр. Но в реальном коде способ создания и уничтожения объектов сильно влияет на:
В этой статье разберём три ключевые темы из духа Effective Java: фабрики (в том числе статические фабричные методы), синглтоны и зависимости, а также практичное уничтожение объектов через управление ресурсами.
!Сравнение прямого создания через new, фабрик и внедрения зависимостей
Фабрики вместо конструкторов
Фабрика — это способ создавать объекты через отдельный метод или отдельный класс, а не напрямую через конструктор. В Java чаще всего под фабрикой имеют в виду статический фабричный метод.
Статические фабричные методы
Статический фабричный метод — это public static метод, который возвращает экземпляр класса.
Пример:
Снаружи это выглядит так:
Почему фабрики часто лучше конструкторов
ofDollars понятнее, чем new Money(500000).Хорошо знакомые примеры из стандартной библиотеки:
Boolean.valueOf(String) может возвращать заранее созданные Boolean.TRUE или Boolean.FALSE.List.of(...) создаёт неизменяемые списки.Ссылки:
Ограничения фабрик
У фабрик тоже есть минусы:
final (иногда это плюс).of(...).Чтобы уменьшить второй минус, придерживаются распространённых имён фабрик:
of(...) — создание из набора параметровvalueOf(...) — преобразование/парсинг в значениеgetInstance() — вернуть экземпляр (возможно один и тот же)newInstance() — обычно обещает новый экземплярgetType() — вернуть объект определённого типа (часто из фабрики)Когда фабрика — это отдельный класс
Иногда создание сложно или зависит от окружения (конфигурации, файлов, сети). Тогда выносите создание в отдельный класс.
Такой подход особенно полезен вместе с внедрением зависимостей: фабрика становится зависимостью, которую можно подменить в тестах.
Синглтоны
Синглтон — это класс, у которого должен существовать ровно один экземпляр (или логически один экземпляр на JVM).
Когда синглтон оправдан
Но синглтоны часто усложняют тестирование и повышают связность. Поэтому прежде чем делать синглтон, спросите себя: можно ли передавать этот объект как зависимость?
Лучший способ: enum-синглтон
Рекомендуемый вариант в Java:
Использование:
Почему это хорошо:
Ссылка:
Классический синглтон через поле
Иногда нужен “обычный” класс. Тогда используют:
Или ленивую инициализацию (когда объект создаётся при первом обращении). Но ленивые варианты легко сделать неправильно с точки зрения потокобезопасности, поэтому применяйте их только осознанно.
Зависимости и внедрение зависимостей
Зависимость — это объект, который вашему классу нужен для работы (например, репозиторий, логгер, клиент внешнего сервиса).
Главная идея: класс не должен сам создавать свои зависимости, если вы хотите гибкость и тестируемость.
Плохой признак: зависимость создаётся внутри
Минусы:
Хороший вариант: передавать зависимость снаружи
Обычно используют внедрение зависимостей через конструктор:
Теперь в продакшене можно передать PostgresUserRepository, а в тестах — InMemoryUserRepository.
Внедрение фабрики или поставщика
Если зависимость создавать дорого, или она нужна не всегда, можно внедрить поставщика (Supplier<T>):
Ссылка:
Синглтон против DI
Частая практическая рекомендация:
Уничтожение объектов: управление ресурсами
В Java обычные объекты уничтожает сборщик мусора (GC). Разработчик обычно не “удаляет” объект вручную.
Но есть отдельный класс объектов: ресурсы, которые держат внешние штуки:
Такие ресурсы нужно закрывать явно.
AutoCloseable и try-with-resources
Если объект реализует AutoCloseable, его можно безопасно закрывать через try-with-resources.
Что важно:
close() вызовется автоматически даже при исключенииСсылки:
Почему не стоит полагаться на finalizer и cleaner
Исторически в Java был механизм finalize(), который мог выполняться перед сборкой мусора. На практике он:
В современных версиях Java финализация считается устаревшим подходом. Если и нужен механизм “страховки”, то он не должен быть основным способом закрытия ресурса.
Практическое правило: ресурс должен закрываться тем кодом, который его открыл, и лучше всего через try-with-resources.
Практические рекомендации
Supplier).AutoCloseable и try-with-resources.В следующей статье логично перейти к теме “контракта методов и классов”: как правильно проектировать equals, hashCode, toString и другие базовые элементы, чтобы созданные объекты корректно работали в коллекциях и логике приложения.