Какие паттерны проектирования вы применяли на практике?

Ответ

Часто используемые паттерны в Java:

  1. Singleton (Одиночка): Гарантирует существование только одного экземпляра класса. Важно учитывать потокобезопасность.

    public class ThreadSafeSingleton {
        private static volatile ThreadSafeSingleton instance;
    
        private ThreadSafeSingleton() {}
    
        public static ThreadSafeSingleton getInstance() {
            if (instance == null) {
                synchronized (ThreadSafeSingleton.class) {
                    if (instance == null) {
                        instance = new ThreadSafeSingleton();
                    }
                }
            }
            return instance;
        }
    }
  2. Factory Method (Фабричный метод): Определяет интерфейс для создания объекта, но оставляет подклассам решение о том, какой класс инстанцировать.

    public interface Notification {
        void notifyUser();
    }
    
    public class EmailNotification implements Notification {
        @Override
        public void notifyUser() {
            System.out.println("Sending an email...");
        }
    }
    
    public abstract class NotificationService {
        // Фабричный метод
        public abstract Notification createNotification();
    
        public void sendNotification() {
            Notification notification = createNotification();
            notification.notifyUser();
        }
    }
  3. Observer (Наблюдатель): Определяет зависимость "один ко многим", чтобы при изменении состояния одного объекта все зависящие от него объекты уведомлялись автоматически. Реализован в Java через java.util.Observable и java.util.Observer (устарели) или через собственную реализацию.

Также активно применяю:

  • Builder: Для пошагового создания сложных объектов (особенно полезен с Lombok @Builder).
  • Strategy: Для инкапсуляции семейства алгоритмов и их взаимозаменяемости.
  • Decorator: Для динамического добавления новой функциональности объектам (реализуется через композицию).
  • Adapter: Для обеспечения совместной работы классов с несовместимыми интерфейсами.

Ответ 18+ 🔞

Слушай, а паттерны-то в Java — это вообще отдельная песня, ебать мои старые костыли! Как будто архитекторы, блядь, сговорились и придумали целый язык для того, чтобы объяснять одно и то же, но разными, ёпта, умными словами. Берёшь обычную идею, обзываешь её на латыни — и вот тебе, сука, паттерн, продавай книжки!

Вот, например, Singleton (Одиночка). Ну что это такое, если не глобальная переменная, но в дорогом костюме, блядь? "Гарантируем один экземпляр!" — орут они. А на деле вся история — это один сплошной геморрой с потокобезопасностью. Смотри, как народ изгаляется, чтобы эту самую одну штуку создать:

public class ThreadSafeSingleton {
    private static volatile ThreadSafeSingleton instance; // volatile, ёпта, чтоб память не кэшировала!

    private ThreadSafeSingleton() {} // Конструктор спрятали, хитрая жопа!

    public static ThreadSafeSingleton getInstance() {
        if (instance == null) { // Первая проверка, чтоб зря в synchronized не лезть
            synchronized (ThreadSafeSingleton.class) { // А вот тут уже серьёзно, блядь
                if (instance == null) { // Вторая проверка, на случай если кто проскочил
                    instance = new ThreadSafeSingleton(); // И только тут рожаем
                }
            }
        }
        return instance;
    }
}

Двойная проверка, volatile, synchronized... Да я один такой экземпляр, блядь, за это время вручную двадцать напишу! Но нет, так "правильно", так "безопасно". Чистый овердохуища церемоний для одной сущности.

Дальше — Factory Method (Фабричный метод). Вообще шедевр, ёперный театр! Смысл-то простой, как три копейки: не вызывай new напрямую, позови какую-нибудь функцию, пусть она тебе объект сделает. Но обрядили это в такую абстракцию, что волосы дыбом!

public interface Notification {
    void notifyUser();
}

public class EmailNotification implements Notification {
    @Override
    public void notifyUser() {
        System.out.println("Sending an email..."); // Тррр-тррр, письмо полетело
    }
}

public abstract class NotificationService {
    // Самый тот самый фабричный метод! Абстрактный, блядь!
    public abstract Notification createNotification();

    public void sendNotification() {
        Notification notification = createNotification(); // О, волшебство! Не знаю что создаст, но создаст!
        notification.notifyUser();
    }
}

И что мы имеем? Родительский класс (NotificationService) говорит: "Я отправлю уведомление, но вот что именно я буду отправлять — это, сынок, твои проблемы, переопределяй метод createNotification". И сидит потом программист, чешет репу: "Так... у меня EmailNotificationService или SmsNotificationService? А, бля, да похуй, главное шаблон соблюсти!"

Ну и вишенка на торте — Observer (Наблюдатель). Это когда один объект (субъект) орет на всю деревню: "Йоу, я изменился!", а куча других объектов (наблюдателей) ему в ответ: "О, спасибо, кэп, теперь и мы что-нибудь сделаем!". В Java даже родные Observable/Observer были, да такие кривые, что их все забили и пишут свои велосипеды. Суть-то проще пареной репы: список подписчиков и метод notifyAll. Но нет, надо же это "паттерном" обозвать!

Из остального, что постоянно юзаю, в рот меня чих-пых:

  • Builder — спасение от конструкторов с десятью параметрами. Особенно с Lombok'ом — аннотацию поставил и живи не тужи. Красота, а не паттерн.
  • Strategy — когда у тебя куча похожих алгоритмов, и ты хочешь тыкать их в объект, как патроны в обойму. Включил нужный — и поехали.
  • Decorator — мощнейшая штука для добавления функциональности. Обернул один объект в другой, потом в третий — и получил слоёный пирог из поведения. Главное — не переборщить, а то будет не декоратор, а манда с ушами.
  • Adapter — классика жанра. Есть старая кривая библиотека, а тебе надо, чтобы она работала с твоим красивым кодом. Пишешь прослойку-адаптер, который превращает кривые вызовы в нормальные. Работа грязная, но кто-то же должен её делать!

В общем, паттерны — это как специи. Посыпал немного — код ароматнее и понятнее стал. Переборщил — есть невозможно, одна горечь и абстракция. Чувство меры, ёпта, главное!