Паттерны проектирования: Singleton - Часть1
Данная статья:
- написана командой Vertex Academy. Надеемся, что она Вам будет полезна. Приятного прочтения!
- это одна из статей из нашего "Самоучителя по Java"
Привет!
В предыдущей статье "Что такое паттерны проектирования в Java" мы рассмотрели что такое паттерн и какие есть паттерны проектирования. В этой статье мы расскажем об одном из самых распространенных паттернов проектирования - Singleton.
Данная статья рассчитана на тех, кто уже хорошо знает ООП.
Что такое Singleton?
Что такое Singleton можно объяснить одной фразой:
Звучит логично, правда? Мы привыкли, что обычно создаем несколько объектов одного класса - вспомним хотя бы String. Но иногда наоборот - что-то необходимо использовать только ОДИН раз. Можно найти примеры этого и в реальной жизни:
- Вы не берете новую ручку каждый раз, когда пишете новое слово?
- Вы не покупаете новый автомобиль каждый раз, когда нужно куда-то ехать?
Вот так и в программировании - иногда нам хватает только одного экземпляра класса для того, чтобы выполнить все поставленные задачи.
Итак, представьте, что в программе Вам нужно:
- получить класс, который имеет всего один экземпляр класса
- в таком случае все, кто обращается к этому классу, будут получать один и тот же экземпляр.
- желательно - для потокобезопасности - должен быть stateless (информацию про stateless можно прочитать тут).
Именно такой класс называется Singleton-ом.
Чем Singleton НЕ ЯВЛЯЕТСЯ?
- Singleton - это не метод, а класс.
- Singleton - это не готовый рецепт создания класса. Есть несколько способов сделать класс синглтоном - мы их рассмотрим далее. Но "начинка" этих классов остается за Вами.
Может ли меняться Singleton?
Да, состояние Singleton-а может быть как изменяемым, так и не изменяемым.
- Пример 1 - изменяемый Singleton
Представьте, что у Вас есть сосед Вася. Вася хакер и хочет взломать Вашу почту. Он подбирает пароли - один за другим - и вводит их по очереди.
Именно для защиты от таких Вась и была придумана блокировка. То есть, например, ввел 5 раз неправильно пароль, все - ты заблокирован - и 30 минут не можешь вводить никакие пароли.
А теперь представим, что именно Вам нужно реализовать систему защиты от таких вот Вась на своем сервере.
Обратите внимание, что множественный ввод не так легко отследить как кажется. На Ваш сервер одновременно поступает огромное количество информации.
Кроме того, Вася может пытаться вводить пароль с разных IP-адресов, что еще больше усложняет задачу. А нам ведь нужно как-то контролировать количество попыток входа в конкретную учетную запись.
В такой ситуации нам как раз и поможет Singleton!
Каждый раз, когда будет запрашиваться доступ к определенной учетной записи, мы будем перенаправлять этот запрос на некий класс, реализующий паттерн Singleton (ведь нам же надо хранить эту информацию только в единственной "точке"). Данный класс будет считать количество неудачных попыток зайти на сайт.
В данном случае наш Singleton будет изменяемым - каждый раз, когда будет осуществляться попытка доступа к нашей учетной записи, переменная, которая считает количество попыток, будет меняться.
Так, чтобы решить эту проблему, нам понадобился изменяемый Singleton.
Пример 2 - неизменяемый Singleton
Одним из примеров неизменяемого Singleton-а может быть класс, который ставит водяной знак (watermark) на изображения, чтобы предотвратить их кражу.
В принципе, поставить вотермарку на изображение - задача достаточно простая. Классу нужно только получить изображение и отдать уже отредактированную картинку. Если водяной знак будет один и тот же на всех изображениях, тогда нет необходимости менять что-либо и в состоянии класса, поэтому он будет неизменяемым. С этой задачей сможет справиться один экземпляр этого класса, а значит можем создать класс на основе паттерна Singleton, который будет выполнять одну и ту же задачу - ставить водяные знаки на изображения.
Несмотря на то, что паттерн Singleton может показаться легким в теории, на практике можно наткнуться на "подводные камни". Давайте посмотрим на примерах.
Как и когда создавать Singleton?
- "Я создаю класс. Мне нужно будет несколько инстансов в будущем или нет?"
Любой класс, которого Вам понадобится только один экземпляр можно сделать Singleton-ом. Вот подумайте - сколько памяти Вы сэкономите... Сколько времени... Ммм... Красота.
- Должен ли Singleton быть доступен из любой точки программы?
В Интернете часто можно увидеть, что Singleton якобы должен быть доступен "из любой точки программы". Это не совсем так. Singleton, как и любые другие данные, должны быть доступны только там, где они нужны. Если они нужны в части программы А - нет необходимости чтобы ее видели части В, C и D.
Тем не менее, обратите внимание на то, какая видимость должна быть у Вашего Singleton-а.
- Обратите внимание - нужно ли Вам работать с потоками.
В зависимости от того, работаете Вы с потоками или нет, можно будет выбрать оптимальную реализацию Singleton-а.
Пример - Самый простой вариант реализации
1 2 3 4 |
public class Singleton { private Singleton(){...} public static final Singleton INSTANCE = new Singleton(); } |
Это самый простой пример реализации Singleton.
Плюсы и минусы
- Честных Singleton в Java не существует 🙂
Из-за reflection, нескольких ClassLoader-ов и других причин, нельзя создать настоящий-настоящий Singleton.
- Трудности при тестировании
Singleton трудно изолировать - это усложняет написание юнит-тестов.
- Нарушает «Принцип единственной обязанности» класса
«Принцип едиственной обязанности» считается хорошим тоном в ООП. Он состоит в том, что класс должен отвечать только за что-то одно. Например, класс "КореньКвадратный" должен отвечать только за извлечения квадратного корня. Он не должен одновременно печь пирог и гладить кота - только извлекать квадратный корень. Класс Singleton, помимо своих прямых обязанностей, занимается контролем количества своих классов. Это считается плохим тоном.
Больше примеров реализации Sigleton-а (их много!) можно посмотреть в нашей следующей статье "Паттерны проектирования: Singleton - Часть 2"
Надеемся, что наша статья была Вам полезна. Можно записаться к нам на курсы по Java на сайте.