The following text is a partial translation of the original English article, performed by ChatGPT (gpt-3.5-turbo) and this Jekyll plugin:
Я думаю, что говорить о том, что синглтон - это антипаттерн, слишком очевидно, так как есть огромное количество статей об этом (о том, что синглтон - антипаттерн). Однако чаще всего вопрос заключается в том, как определить глобальные объекты без использования синглтона, и ответ на этот вопрос не очевиден для многих из нас. Существует несколько примеров: пул подключений к базе данных, репозиторий, карта конфигурации и т. д. Все они естественным образом кажутся “глобальными”, но что мы с ними делаем?
Я предполагаю, что вы уже знаете, что такое синглтон и почему это антипаттерн. Если нет, я рекомендую вам прочитать эту тему на Stack Overflow: Что так плохо в синглтонах?
Теперь, когда мы согласились, что это плохо, что делаем, если нам нужно, скажем, иметь доступ к пулу подключений к базе данных во многих разных местах в приложении? Нам просто нужно что-то вроде этого:
Позднее, скажем, в методе JAX-RS REST, нам нужно извлечь что-то из базы данных.
Если вы не знакомы с JAX-RS, это простая архитектура MVC, и этот метод text()
- “контроллер”. Кроме того, я использую JdbcSession
, простую оболочку JDBC из jcabi-jdbc.
Нам нужно, чтобы Database.INSTANCE
был синглтоном, верно? Нам нужно, чтобы он был глобально доступным, чтобы любой контроллер MVC имел к нему прямой доступ. Поскольку мы все понимаем и соглашаемся, что синглтон - это зло, на что его заменить?
Ответ - внедрение зависимости.
Мы должны сделать этот пул подключений к базе данных зависимостью контроллера и убедиться, что он предоставляется через конструктор. Однако, в данном случае, для JAX-RS, мы не можем сделать это через конструктор из-за его некрасивой архитектуры. Но мы можем создать ServletContextListener
, создать экземпляр Database
в его методе contextInitialized()
и добавить этот экземпляр как атрибут servletContext
. Затем, внутри контроллера, мы получаем контекст сервлета, добавляя аннотацию javax.ws.rs.core.Context
к сеттеру и используя getAttribute()
на нем. Это абсолютно ужасно и процедурно, но лучше, чем синглтон.
Правильный объектно-ориентированный дизайн предполагает передачу экземпляра Database
всем объектам, которым он может понадобиться, через их конструкторы.
Тем не менее, что делать, если есть много зависимостей? Создавать конструктор с 10 аргументами? Нет, не нужно. Если нашим объектам действительно нужно 10 зависимостей для выполнения их работы, нам нужно разбить их на более мелкие.
Вот и все. Забудьте о синглтонах; никогда не используйте их. Превратите их в зависимости и передавайте их от объекта к объекту с помощью оператора new
.
Translated by ChatGPT gpt-3.5-turbo/42 on 2023-11-17 at 14:46