🏗 Порождающие паттерны: Как рождаются объекты?
Создать объект просто:
А если у объекта 20 полей? А если нам нужен только один экземпляр на всё приложение? А если мы не знаем заранее, какой именно класс нам нужен?
Тут на сцену выходят паттерны.
1️⃣ Singleton (Одиночка)
Суть: Гарантирует, что у класса есть только один экземпляр, и предоставляет к нему глобальную точку доступа.
Где нужен: Логгеры, Конфигурация, Пул соединений с БД.
Как реализовать:
1. Скрываем конструктор (
2. Создаем статическое поле с экземпляром.
3. Возвращаем его через статический метод.
⚠️ Важно: В Spring Boot все бины по умолчанию - синглтоны. Вам не нужно писать этот код руками, контейнер Spring сам следит, чтобы сервис был создан один раз.
2️⃣ Builder (Строитель)
Суть: Позволяет создавать сложные объекты пошагово. Спасает от «Телескопического конструктора» (когда у вас конструктор с 10 аргументами, и вы не помните, где там
Было (Ужас):
Стало (Builder):
🛠 Лайфхак:
В Java не нужно писать Билдер руками (это 50 строк кода). Просто поставьте аннотацию Lombok
3️⃣ Factory Method (Фабричный метод)
Суть: Определяет интерфейс для создания объекта, но оставляет подклассам решение о том, какой класс инстанцировать.
Это реализация принципа Open-Closed. Мы добавляем новые типы продуктов, не ломая существующий код.
Пример: У нас есть "Уведомления". Сегодня это Email, завтра SMS, послезавтра Push.
🔥 Итог
1. Singleton - когда нужен один объект на всю систему.
2. Builder - когда объект сложный и у него много параметров.
3. Factory - когда мы не знаем заранее, какой конкретно объект понадобится, или хотим скрыть логику выбора.
#DesignPatterns #GoF #Singleton #Builder #Factory #Java
📲 Мы в MAX
👉@BookJava
Создать объект просто:
User u = new User().А если у объекта 20 полей? А если нам нужен только один экземпляр на всё приложение? А если мы не знаем заранее, какой именно класс нам нужен?
Тут на сцену выходят паттерны.
1️⃣ Singleton (Одиночка)
Суть: Гарантирует, что у класса есть только один экземпляр, и предоставляет к нему глобальную точку доступа.
Где нужен: Логгеры, Конфигурация, Пул соединений с БД.
Как реализовать:
1. Скрываем конструктор (
private).2. Создаем статическое поле с экземпляром.
3. Возвращаем его через статический метод.
public class Database {
// Единственный экземпляр
private static Database instance;
private Database() {} // Никто не создаст объект извне
public static synchronized Database getInstance() {
if (instance == null) {
instance = new Database();
}
return instance;
}
}
⚠️ Важно: В Spring Boot все бины по умолчанию - синглтоны. Вам не нужно писать этот код руками, контейнер Spring сам следит, чтобы сервис был создан один раз.
2️⃣ Builder (Строитель)
Суть: Позволяет создавать сложные объекты пошагово. Спасает от «Телескопического конструктора» (когда у вас конструктор с 10 аргументами, и вы не помните, где там
age, а где height).Было (Ужас):
new User("Alex", null, true, "admin", 25, null);Стало (Builder):
User user = User.builder()
.name("Alex")
.age(25)
.role("ADMIN")
.active(true)
.build();
🛠 Лайфхак:
В Java не нужно писать Билдер руками (это 50 строк кода). Просто поставьте аннотацию Lombok
@Builder над классом.3️⃣ Factory Method (Фабричный метод)
Суть: Определяет интерфейс для создания объекта, но оставляет подклассам решение о том, какой класс инстанцировать.
Это реализация принципа Open-Closed. Мы добавляем новые типы продуктов, не ломая существующий код.
Пример: У нас есть "Уведомления". Сегодня это Email, завтра SMS, послезавтра Push.
// 1. Интерфейс
interface Notification { void send(String msg); }
// 2. Реализации
class EmailNotification implements Notification { ... }
class SmsNotification implements Notification { ... }
// 3. Фабрика (Решает, что создать)
class NotificationFactory {
public static Notification create(String type) {
return switch (type) {
case "EMAIL" -> new EmailNotification();
case "SMS" -> new SmsNotification();
default -> throw new IllegalArgumentException("Unknown type");
};
}
}
// Клиентский код (не знает про классы Email/Sms, знает только интерфейс)
Notification notification = NotificationFactory.create("SMS");
notification.send("Hello!");
🔥 Итог
1. Singleton - когда нужен один объект на всю систему.
2. Builder - когда объект сложный и у него много параметров.
3. Factory - когда мы не знаем заранее, какой конкретно объект понадобится, или хотим скрыть логику выбора.
#DesignPatterns #GoF #Singleton #Builder #Factory #Java
📲 Мы в MAX
👉@BookJava
👍5🔥3
🏗 Структурные паттерны: Адаптер, Декоратор, Прокси
Когда вы пытаетесь соединить старую библиотеку с новым кодом или добавить логирование, не переписывая половину проекта - вы используете эти паттерны.
🔌 1. Adapter (Адаптер)
Суть: Делает несовместимые интерфейсы совместимыми.
Это как переходник для розетки. У вас вилка американская, а розетка европейская. Адаптер позволяет им работать вместе.
Где нужен: Когда есть старый класс (Legacy), который нельзя менять, но его нужно использовать в новом коде.
Пример: У нас есть система, которая понимает только
🎁 2. Decorator (Декоратор/Обертка)
Суть: Динамически добавляет объекту новые обязанности (функционал).
Это альтернатива наследованию. Вместо того чтобы создавать
Принцип: Матрешка. Каждый декоратор делает свою работу и вызывает следующий.
Пример:
Важно: В
🛡️ 3. Proxy (Заместитель)
Суть: Объект-прокладка, который контролирует доступ к другому объекту.
Клиент думает, что общается с реальным объектом, а на самом деле говорит с его заместителем.
Зачем?
1. Ленивая загрузка (Lazy Loading): Не грузить тяжелую картинку/БД, пока ее реально не попросят.
2. Безопасность: Проверить права доступа перед выполнением метода.
3. Логирование: Записать "Метод вызван" и передать вызов дальше.
Пример:
Spring Magic: Весь Spring держится на Прокси! Когда вы ставите
🔥 Итог
🔴 Adapter - меняет интерфейс объекта (чтобы подошел).
🔴 Decorator - меняет поведение объекта (добавляет фичи), не меняя интерфейс.
🔴 Proxy - контролирует доступ к объекту (ленивость, защита).
#DesignPatterns #Adapter #Decorator #Proxy #Architecture
📲 Мы в MAX
👉@BookJava
Когда вы пытаетесь соединить старую библиотеку с новым кодом или добавить логирование, не переписывая половину проекта - вы используете эти паттерны.
🔌 1. Adapter (Адаптер)
Суть: Делает несовместимые интерфейсы совместимыми.
Это как переходник для розетки. У вас вилка американская, а розетка европейская. Адаптер позволяет им работать вместе.
Где нужен: Когда есть старый класс (Legacy), который нельзя менять, но его нужно использовать в новом коде.
Пример: У нас есть система, которая понимает только
KM/H (километры), а внешняя библиотека выдает скорость в MPH (мили).
// 1. Наш интерфейс (чего мы ждем)
interface Movable { double getSpeed(); } // км/ч
// 2. Чужой класс (что есть)
class Bugatti {
double getSpeedMph() { return 268; }
}
// 3. Адаптер (Переводчик)
class MovableAdapter implements Movable {
private Bugatti bugatti;
public MovableAdapter(Bugatti bugatti) {
this.bugatti = bugatti;
}
@Override
public double getSpeed() {
return convertMphToKmph(bugatti.getSpeedMph());
}
}
🎁 2. Decorator (Декоратор/Обертка)
Суть: Динамически добавляет объекту новые обязанности (функционал).
Это альтернатива наследованию. Вместо того чтобы создавать
CoffeeWithMilkAndSugar, мы берем Coffee и заворачиваем его в Milk, а потом в Sugar.Принцип: Матрешка. Каждый декоратор делает свою работу и вызывает следующий.
Пример:
// Базовый кофе
Coffee coffee = new SimpleCoffee();
System.out.println(coffee.getCost()); // 10$
// Добавили молоко (Обернули)
coffee = new MilkDecorator(coffee);
System.out.println(coffee.getCost()); // 12$
// Добавили сахар (Обернули еще раз)
coffee = new SugarDecorator(coffee);
System.out.println(coffee.getCost()); // 13$
Важно: В
java.io это используется повсюду: new BufferedReader(new FileReader(file)).🛡️ 3. Proxy (Заместитель)
Суть: Объект-прокладка, который контролирует доступ к другому объекту.
Клиент думает, что общается с реальным объектом, а на самом деле говорит с его заместителем.
Зачем?
1. Ленивая загрузка (Lazy Loading): Не грузить тяжелую картинку/БД, пока ее реально не попросят.
2. Безопасность: Проверить права доступа перед выполнением метода.
3. Логирование: Записать "Метод вызван" и передать вызов дальше.
Пример:
interface Image { void display(); }
class RealImage implements Image {
public RealImage(String file) { loadFromDisk(file); } // Долгая операция!
public void display() { System.out.println("Displaying..."); }
}
class ProxyImage implements Image {
private RealImage realImage;
private String file;
public ProxyImage(String file) { this.file = file; }
@Override
public void display() {
if (realImage == null) {
realImage = new RealImage(file); // Грузим только сейчас!
}
realImage.display();
}
}
Spring Magic: Весь Spring держится на Прокси! Когда вы ставите
@Transactional, Spring создает прокси вокруг вашего сервиса, открывает транзакцию, вызывает ваш метод, а потом закрывает транзакцию.🔥 Итог
#DesignPatterns #Adapter #Decorator #Proxy #Architecture
📲 Мы в MAX
👉@BookJava
Please open Telegram to view this post
VIEW IN TELEGRAM
👍7
🧠 Поведенческие паттерны: Стратегия, Наблюдатель, Цепочка
Эти паттерны помогают избежать спагетти-кода, где один класс управляет всем миром через гигантские
🗺 1. Strategy (Стратегия)
Суть: Позволяет менять алгоритм поведения объекта прямо "на лету", во время выполнения программы.
Это убийца бесконечных
Аналогия: Навигатор. Вы строите маршрут из точки А в точку Б. Стратегия - это способ передвижения:
🔴 Пешком (один алгоритм).
🔴 На машине (другой алгоритм).
🔴 На автобусе (третий алгоритм).
Цель одна, пути реализации разные.
Код:
👀 2. Observer (Наблюдатель / Listener)
Суть: Один объект (Subject) меняет свое состояние, и все зависимые от него объекты (Observers) тут же узнают об этом.
Аналогия: YouTube-канал.
🔴 Блогер (Subject) выпускает видео.
🔴 Подписчики (Observers) получают уведомление.
🔴 Если вы отписались - уведомления приходить перестанут.
Код: Это основа всех UI-фреймворков (кнопка нажата -> слушатель сработал) и даже архитектуры Kafka.
🔗 3. Chain of Responsibility (Цепочка обязанностей)
Суть: Запрос передается по цепочке обработчиков. Каждый обработчик решает: обработать запрос самому или передать следующему.
Аналогия: Техподдержка.
1. Сначала отвечает Чат-бот (Уровень 1). Не справился? -> Передает дальше.
2. Оператор колл-центра (Уровень 2). Не справился? -> Передает дальше.
3. Инженер (Уровень 3). Решает проблему.
Пример в Spring:
Spring Security работает именно так! Ваш HTTP-запрос проходит через цепочку фильтров:
🔴
Если хоть один фильтр скажет "Нет", запрос дальше не пойдет.
Код:
🔥 Итог
🔴 Strategy - Выбираем алгоритм действия (Платим картой или кэшем?).
🔴 Observer - Слушаем изменения (Вышло видео -> пришло уведомление).
🔴 Chain of Responsibility - Передаем эстафету (Фильтр 1 -> Фильтр 2 -> Контроллер).
#DesignPatterns #Behavioral #Strategy #Observer #ChainOfResponsibility
📲 Мы в MAX
👉@BookJava
Эти паттерны помогают избежать спагетти-кода, где один класс управляет всем миром через гигантские
if-else.🗺 1. Strategy (Стратегия)
Суть: Позволяет менять алгоритм поведения объекта прямо "на лету", во время выполнения программы.
Это убийца бесконечных
if (type == "CARD") { ... } else if (type == "PAYPAL") { ... }.Аналогия: Навигатор. Вы строите маршрут из точки А в точку Б. Стратегия - это способ передвижения:
Цель одна, пути реализации разные.
Код:
// Общий интерфейс
interface RouteStrategy {
void buildRoute(String a, String b);
}
// Конкретные стратегии
class RoadStrategy implements RouteStrategy { ... }
class WalkingStrategy implements RouteStrategy { ... }
// Контекст (Навигатор)
class Navigator {
private RouteStrategy strategy;
public void setStrategy(RouteStrategy strategy) {
this.strategy = strategy; // Меняем на лету!
}
public void buildRoute(String a, String b) {
strategy.buildRoute(a, b);
}
}
👀 2. Observer (Наблюдатель / Listener)
Суть: Один объект (Subject) меняет свое состояние, и все зависимые от него объекты (Observers) тут же узнают об этом.
Аналогия: YouTube-канал.
Код: Это основа всех UI-фреймворков (кнопка нажата -> слушатель сработал) и даже архитектуры Kafka.
class NewsAgency {
private List<Channel> channels = new ArrayList<>();
public void subscribe(Channel channel) {
channels.add(channel);
}
public void broadcast(String news) {
for (Channel channel : channels) {
channel.update(news); // Уведомляем всех!
}
}
}
🔗 3. Chain of Responsibility (Цепочка обязанностей)
Суть: Запрос передается по цепочке обработчиков. Каждый обработчик решает: обработать запрос самому или передать следующему.
Аналогия: Техподдержка.
1. Сначала отвечает Чат-бот (Уровень 1). Не справился? -> Передает дальше.
2. Оператор колл-центра (Уровень 2). Не справился? -> Передает дальше.
3. Инженер (Уровень 3). Решает проблему.
Пример в Spring:
Spring Security работает именно так! Ваш HTTP-запрос проходит через цепочку фильтров:
CorsFilter (проверяет домен) -> JwtFilter (проверяет токен) -> UsernamePasswordFilter (проверяет логин).Если хоть один фильтр скажет "Нет", запрос дальше не пойдет.
Код:
abstract class SupportHandler {
protected SupportHandler next;
public void setNext(SupportHandler next) { this.next = next; }
public void handleRequest(String issue) {
if (canHandle(issue)) {
solve();
} else if (next != null) {
next.handleRequest(issue); // Передаем следующему
}
}
}
🔥 Итог
#DesignPatterns #Behavioral #Strategy #Observer #ChainOfResponsibility
📲 Мы в MAX
👉@BookJava
Please open Telegram to view this post
VIEW IN TELEGRAM
👍5