Singletons Must Die

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

sixnines availability badge   GitHub stars