Библиотека собеса по Java | вопросы с собеседований
6.49K subscribers
419 photos
10 videos
679 links
Вопросы с собеседований по Java и ответы на них.

По рекламе: @proglib_adv

Учиться у нас: clc.to/3wECtA

Для обратной связи: @proglibrary_feeedback_bot
Download Telegram
Расскажите о паттерне Strategy?

Strategy — это поведенческий паттерн, который позволяет определить семейство алгоритмов, инкапсулировать каждый из них и сделать их взаимозаменяемыми.

Когда использовать:

есть несколько способов выполнения одной операции;
нужно избежать множественных if-else или switch;
алгоритмы должны выбираться в runtime.

Преимущества: соблюдение Open/Closed Principle, устранение условных операторов, гибкость выбора алгоритма.

🐸 Библиотека собеса по Java

#patterns
Please open Telegram to view this post
VIEW IN TELEGRAM
👍83🔥21
Расскажите о паттерне Singleton?

Singleton — это порождающий паттерн проектирования, который гарантирует, что у класса существует только один экземпляр, и предоставляет глобальную точку доступа к нему.

🔹 Основные характеристики:

приватный конструктор запрещает создание экземпляров извне;
статический метод getInstance() возвращает единственный экземпляр;
статическое поле для хранения экземпляра.

🔹 Когда использовать:

объект содержит глобальное состояние;
создание объекта ресурсозатратно;
нужен единый координатор действий;
логически должен быть один экземпляр.

🐸 Библиотека собеса по Java

#patterns
Please open Telegram to view this post
VIEW IN TELEGRAM
4👍3🔥1
Расскажите о паттерне Adapter

Adapter (Адаптер) — это структурный паттерн проектирования, который позволяет объектам с несовместимыми интерфейсами работать вместе. Он выступает в роли "переходника" между двумя интерфейсами.

🔹 Когда использовать:

Когда нужно использовать существующий класс, но его интерфейс не соответствует требуемому. Например, при интеграции сторонних библиотек или работе с легаси-кодом.

🐸 Библиотека собеса по Java

#patterns
Please open Telegram to view this post
VIEW IN TELEGRAM
👍7🔥1🤔1
Расскажите о паттерне Factory Method

Factory Method — порождающий паттерн, который определяет общий интерфейс для создания объектов в суперклассе, позволяя подклассам изменять тип создаваемых объектов.

🔹 Когда использовать:

Когда заранее неизвестны типы и зависимости объектов, или когда нужно делегировать создание объектов подклассам.

🔹 Как работает:

Создается абстрактный метод для создания объектов, а конкретные подклассы переопределяют его, возвращая нужные типы.

🔹 Плюсы:

избавляет от привязки к конкретным классам;
упрощает добавление новых типов продуктов;
следует Open/Closed Principle.

🐸 Библиотека собеса по Java

#patterns
Please open Telegram to view this post
VIEW IN TELEGRAM
👍73🔥1
Расскажите о паттерне Abstract Factory

Abstract Factory — это порождающий паттерн, который создает семейства связанных объектов без привязки к конкретным классам.
Простыми словами: вы создаете не один объект, а целый набор совместимых между собой объектов.

▪️ Пример:

Система уведомлений, которая работает с разными провайдерами (AWS, Firebase). Для каждого провайдера нужны свои клиенты для отправки email, SMS и push-уведомлений.

// Абстрактные продукты
interface EmailSender {
void send(String to, String message);
}

interface SmsSender {
void send(String phone, String message);
}

// Абстрактная фабрика
interface NotificationFactory {
EmailSender createEmailSender();
SmsSender createSmsSender();
}

// AWS реализация
class AwsEmailSender implements EmailSender {
public void send(String to, String message) {
System.out.println("Отправка через AWS SES: " + to);
}
}

class AwsSmsSender implements SmsSender {
public void send(String phone, String message) {
System.out.println("Отправка через AWS SNS: " + phone);
}
}

class AwsNotificationFactory implements NotificationFactory {
public EmailSender createEmailSender() {
return new AwsEmailSender();
}

public SmsSender createSmsSender() {
return new AwsSmsSender();
}
}

// Аналогично FirebaseNotificationFactory...

// Использование
NotificationFactory factory = new AwsNotificationFactory();
EmailSender email = factory.createEmailSender();
SmsSender sms = factory.createSmsSender();
// Гарантия: оба сервиса работают через AWS


▪️ В чем отличие от Factory Method

— Factory Method создает один продукт
— Abstract Factory создает семейство продуктов (email + sms + push)

▪️ Когда использовать

Когда нужны наборы связанных объектов, которые должны работать вместе (клиенты для разных облаков, драйверы БД, парсеры форматов).

▪️ Минус

Сложно добавить новый тип продукта — придется менять все фабрики.

🐸 Библиотека собеса по Java

#patterns
Please open Telegram to view this post
VIEW IN TELEGRAM
3👍3🔥1
Расскажите о паттерне Prototype

Prototype — это порождающий паттерн, который позволяет копировать объекты, не вдаваясь в подробности их реализации.

Простыми словами: вместо создания объекта с нуля через конструктор, вы клонируете уже существующий экземпляр.

▪️ Пример:

Система отчетов, где базовая конфигурация отчета сложная (подключение к БД, загрузка шаблонов, настройка форматирования). Вместо каждый раз создавать отчет заново, клонируем прототип.
// Прототип
abstract class Report implements Cloneable {
protected String template;
protected DatabaseConnection dbConnection;
protected Map<String, Object> settings;

// Сложная инициализация
public Report() {
this.dbConnection = new DatabaseConnection(); // затратная операция
this.settings = loadDefaultSettings(); // загрузка из файла
}

@Override
public Report clone() {
try {
Report cloned = (Report) super.clone();
// Глубокое копирование для изменяемых полей
cloned.settings = new HashMap<>(this.settings);
return cloned;
} catch (CloneNotSupportedException e) {
throw new RuntimeException(e);
}
}

abstract void generate();
}

class SalesReport extends Report {
void generate() {
System.out.println("Генерация отчета по продажам");
}
}

// Использование
Report prototype = new SalesReport(); // долгая инициализация

// Быстрое создание копий
Report report1 = prototype.clone();
Report report2 = prototype.clone();
report2.settings.put("period", "Q2"); // изменяем только нужные параметры


▪️ Когда использовать

Создание объекта затратно (сложная инициализация, обращение к БД, парсинг файлов)
Нужно избежать привязки к конкретным классам при создании копий
Объекты различаются только состоянием, а не поведением

▪️ Важно: Shallow vs Deep Copy

Shallow copy — копируются только примитивы, ссылки на объекты остаются теми же
Deep copy — создаются копии вложенных объектов

▪️ Альтернативы clone()

— Copy constructor: new Report(original)
— Статический метод: Report.copy(original)
— Сериализация: для очень сложных объектов

▪️ Минус

Клонирование объектов с циклическими ссылками может быть сложным.

🐸 Библиотека собеса по Java

#patterns
Please open Telegram to view this post
VIEW IN TELEGRAM
👍52🔥1
Расскажите о паттерне Flyweight

Flyweight — это структурный паттерн, который позволяет вместить большее количество объектов в отведённую оперативную память за счёт разделения общего состояния между объектами.

Простыми словами: вместо создания тысяч похожих объектов, вы создаёте несколько объектов-легковесов с общими данными и передаёте уникальные данные извне при использовании.

▪️ Пример

Текстовый редактор, где каждая буква — это объект. Если создавать отдельный объект для каждой буквы с полным набором свойств (шрифт, размер, цвет), миллион символов займут гигабайты памяти.

// Flyweight — легковес с общим состоянием
class CharacterStyle {
private final String font; // внутреннее состояние
private final int size; // (intrinsic)
private final String color;
public CharacterStyle(String font, int size, String color) {
this.font = font;
this.size = size;
this.color = color;
}

public void render(char character, int x, int y) { // внешнее состояние
System.out.println("Рендер '" + character +
"' в позиции (" + x + "," + y + ")");
}
}
// Фабрика для переиспользования flyweight-объектов
class StyleFactory {
private Map<String, CharacterStyle> styles = new HashMap<>();
public CharacterStyle getStyle(String font, int size, String color) {
String key = font + size + color;
return styles.computeIfAbsent(key,
k -> new CharacterStyle(font, size, color));
}
}
// Использование
StyleFactory factory = new StyleFactory();
// Миллион символов используют всего несколько объектов стилей
CharacterStyle arial12 = factory.getStyle("Arial", 12, "black");
arial12.render('H', 0, 0);
arial12.render('e', 10, 0);
arial12.render('l', 20, 0);
arial12.render('l', 30, 0);
arial12.render('o', 40, 0);


▪️ Когда использовать


Приложение создаёт огромное количество однотипных объектов
Объекты потребляют много памяти
Большую часть состояния можно вынести за пределы объекта
Приложение не зависит от идентичности объектов (можно переиспользовать)

▪️ Минусы

Усложнение кода из-за разделения состояния
Flyweight должен быть immutable для безопасного переиспользования

🐸 Библиотека собеса по Java

#patterns
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥4👍21
Расскажите о паттерне Builder

Builder — это порождающий паттерн, который позволяет создавать сложные объекты пошагово, разделяя процесс конструирования и представление.

Простыми словами: вместо конструктора с десятком параметров, вы собираете объект по частям, вызывая понятные методы.

▪️ Пример:

HTTP-клиент с множеством необязательных настроек: таймауты, заголовки, ретраи, прокси. Конструктор с 10 параметрами нечитаем, а Builder решает это.

public class HttpClient {
private final String baseUrl;
private final int connectTimeout;
private final int readTimeout;
private final Map<String, String> headers;
private final int maxRetries;

private HttpClient(Builder builder) {
this.baseUrl = builder.baseUrl;
this.connectTimeout = builder.connectTimeout;
this.readTimeout = builder.readTimeout;
this.headers = builder.headers;
this.maxRetries = builder.maxRetries;
}

public static class Builder {
private final String baseUrl; // обязательный
private int connectTimeout = 5000; // значение по умолчанию
private int readTimeout = 10000;
private Map<String, String> headers = new HashMap<>();
private int maxRetries = 3;

public Builder(String baseUrl) {
this.baseUrl = baseUrl;
}

public Builder connectTimeout(int ms) {
this.connectTimeout = ms;
return this;
}

public Builder readTimeout(int ms) {
this.readTimeout = ms;
return this;
}

public Builder header(String key, String value) {
this.headers.put(key, value);
return this;
}

public Builder maxRetries(int retries) {
this.maxRetries = retries;
return this;
}

public HttpClient build() {
return new HttpClient(this);
}
}
}

// Использование
HttpClient client = new HttpClient.Builder("https://api.example.com")
.connectTimeout(3000)
.header("Authorization", "Bearer token")
.maxRetries(5)
.build();


▪️ Когда использовать

Объект имеет множество параметров (особенно необязательных)
Нужна immutable-объект с удобным созданием
Хотите избежать telescoping constructor (конструктор в конструкторе)

▪️ Builder vs конструктор

— Конструктор: подходит, если параметров 2–3 и все обязательные
— Builder: если параметров больше 4 или есть необязательные

▪️ Минус

Дублирование полей между классом и билдером. Lombok @Builder решает это автоматически.

🐸 Библиотека собеса по Java

#patterns
Please open Telegram to view this post
VIEW IN TELEGRAM
👍32🔥1🤔1
Расскажите о паттерне Bridge

Bridge — это структурный паттерн, который разделяет абстракцию и реализацию так, чтобы они могли изменяться независимо друг от друга.

Простыми словами: вместо одной толстой иерархии наследования вы разбиваете её на две независимые — «что делать» и «как делать» — и связываете их композицией.

▪️ Пример:

Система отправки уведомлений: типы уведомлений (срочное, обычное) × каналы доставки (email, SMS, push). Без Bridge это 6 классов, с каждым новым каналом — взрывной рост.

// Реализация — «как доставить»
interface MessageSender {
void send(String message, String recipient);
}

class EmailSender implements MessageSender {
public void send(String message, String recipient) {
System.out.println("Email → " + recipient + ": " + message);
}
}

class SmsSender implements MessageSender {
public void send(String message, String recipient) {
System.out.println("SMS → " + recipient + ": " + message);
}
}

// Абстракция — «что отправить»
abstract class Notification {
protected MessageSender sender; // мост к реализации

public Notification(MessageSender sender) {
this.sender = sender;
}

abstract void notify(String recipient, String message);
}

class UrgentNotification extends Notification {
public UrgentNotification(MessageSender sender) {
super(sender);
}

void notify(String recipient, String message) {
sender.send("[СРОЧНО] " + message, recipient);
sender.send("[СРОЧНО] Повторное напоминание: " + message, recipient);
}
}

class RegularNotification extends Notification {
public RegularNotification(MessageSender sender) {
super(sender);
}

void notify(String recipient, String message) {
sender.send(message, recipient);
}
}

// Использование — любая комбинация
Notification urgentSms = new UrgentNotification(new SmsSender());
urgentSms.notify("+79991234567", "Сервер упал");

Notification regularEmail = new RegularNotification(new EmailSender());
regularEmail.notify("dev@company.com", "Деплой завершён");


▪️ Когда использовать

Есть две ортогональные оси изменения (тип × реализация)
Хотите избежать «взрыва» подклассов
Нужно переключать реализацию в runtime

▪️ Bridge vs Strategy

— Strategy: меняет один алгоритм внутри объекта
— Bridge: разделяет целые иерархии абстракции и реализации

▪️ Минус

Усложняет код, если оси изменения всего одна — тогда достаточно обычного полиморфизма.

🐸 Библиотека собеса по Java

#patterns
Please open Telegram to view this post
VIEW IN TELEGRAM
👍63🔥1
Расскажите о паттерне Composite

Composite — это структурный паттерн, который позволяет сгруппировать объекты в древовидную структуру и работать с ней так же, как с единичным объектом.

Простыми словами: файл и папка с файлами обрабатываются одинаково — у обоих можно спросить размер, удалить, переместить.

▪️ Пример:

Структура отдела в компании: сотрудник и команда состоят в одной иерархии. Нужно посчитать общую зарплату по любой ветке.

// Общий интерфейс
interface OrganizationUnit {
String getName();
long getSalary();
}

// Лист — отдельный сотрудник
class Employee implements OrganizationUnit {
private final String name;
private final long salary;

public Employee(String name, long salary) {
this.name = name;
this.salary = salary;
}

public String getName() { return name; }
public long getSalary() { return salary; }
}

// Композит — отдел, содержит другие элементы
class Department implements OrganizationUnit {
private final String name;
private final List<OrganizationUnit> units = new ArrayList<>();

public Department(String name) {
this.name = name;
}

public void add(OrganizationUnit unit) {
units.add(unit);
}

public String getName() { return name; }

public long getSalary() {
return units.stream()
.mapToLong(OrganizationUnit::getSalary)
.sum();
}
}

// Использование
Department dev = new Department("Разработка");
dev.add(new Employee("Анна", 200_000));
dev.add(new Employee("Борис", 180_000));

Department company = new Department("Компания");
company.add(dev);
company.add(new Employee("CEO Иван", 500_000));

System.out.println(company.getSalary()); // 880000


▪️ Когда использовать

Данные образуют древовидную структуру (файловая система, меню, оргструктура)
Клиентский код должен одинаково работать с простыми и составными объектами

▪️ Минус

Трудно ограничить типы компонентов внутри композита — приходится проверять в runtime.

🐸 Библиотека собеса по Java

#patterns
Please open Telegram to view this post
VIEW IN TELEGRAM
👍61🔥1
Расскажите о паттерне Decorator

Decorator — это структурный паттерн, позволяющий на лету расширять поведение объекта, не изменяя его класс. Исходный объект помещается внутрь другого — декоратора, — который перехватывает вызовы и дополняет их нужной функциональностью.

Принцип тот же, что у матрёшки: каждый новый слой добавляет что-то своё.

▪️ Пример:

Сервис обработки данных: базовая загрузка, поверх — логирование, поверх — кэширование. Каждый слой добавляется независимо.

// Базовый интерфейс
interface DataService {
String getData(String key);
}

// Базовая реализация
class DatabaseService implements DataService {
public String getData(String key) {
return "data_from_db_" + key; // запрос в БД
}
}

// Абстрактный декоратор
abstract class DataServiceDecorator implements DataService {
protected final DataService delegate;

public DataServiceDecorator(DataService delegate) {
this.delegate = delegate;
}
}

// Декоратор логирования
class LoggingDecorator extends DataServiceDecorator {
public LoggingDecorator(DataService delegate) {
super(delegate);
}

public String getData(String key) {
System.out.println("LOG: запрос ключа " + key);
String result = delegate.getData(key);
System.out.println("LOG: получен результат");
return result;
}
}

// Декоратор кэширования
class CachingDecorator extends DataServiceDecorator {
private final Map<String, String> cache = new HashMap<>();

public CachingDecorator(DataService delegate) {
super(delegate);
}

public String getData(String key) {
return cache.computeIfAbsent(key, delegate::getData);
}
}

// Использование — собираем как конструктор
DataService service = new CachingDecorator(
new LoggingDecorator(
new DatabaseService()
)
);

service.getData("user:42"); // лог + БД + кэш
service.getData("user:42"); // кэш (без лога и БД)


▪️ Когда использовать

Нужно добавить поведение объекту без наследования
Комбинации поведений непредсказуемы (логирование + кэш + метрики в любом порядке)
Классический пример в JDK: InputStream → BufferedInputStream → GZIPInputStream

▪️ Decorator vs наследование

— Наследование: статическое, одно на класс
— Decorator: динамическое, можно комбинировать

▪️ Минус

Много мелких классов; отладка стека из нескольких обёрток может быть неудобной.

🐸 Библиотека собеса по Java

#patterns
Please open Telegram to view this post
VIEW IN TELEGRAM
3👍3🔥1
Расскажите о паттерне Facade

Facade — это структурный паттерн, который предоставляет простой интерфейс к сложной подсистеме, скрывая внутреннюю сложность.

Простыми словами: один метод вместо десяти вызовов в разные сервисы. Пульт от телевизора — это фасад к электронике внутри.

▪️ Пример:

Оформление заказа: нужно проверить наличие, списать деньги, создать доставку, отправить уведомление. Клиент не должен знать эти детали.

// Сложная подсистема
class InventoryService {
boolean checkStock(String productId) {
return true; // проверка на складе
}
}

class PaymentService {
boolean charge(String userId, BigDecimal amount) {
return true; // списание средств
}
}

class ShippingService {
String createShipment(String orderId, String address) {
return "TRACK-" + orderId; // создание доставки
}
}

class NotificationService {
void sendOrderConfirmation(String userId, String trackingId) {
System.out.println("Уведомление отправлено: " + trackingId);
}
}

// Фасад — один метод вместо четырёх
class OrderFacade {
private final InventoryService inventory = new InventoryService();
private final PaymentService payment = new PaymentService();
private final ShippingService shipping = new ShippingService();
private final NotificationService notification = new NotificationService();

public String placeOrder(String userId, String productId,
BigDecimal amount, String address) {
if (!inventory.checkStock(productId)) {
throw new IllegalStateException("Нет на складе");
}
if (!payment.charge(userId, amount)) {
throw new IllegalStateException("Оплата не прошла");
}
String trackingId = shipping.createShipment(productId, address);
notification.sendOrderConfirmation(userId, trackingId);
return trackingId;
}
}

// Клиент вызывает один метод
OrderFacade facade = new OrderFacade();
String tracking = facade.placeOrder("user1", "SKU-100",
new BigDecimal("2999.00"), "Москва, ул. Пушкина");


▪️ Когда использовать

Подсистема сложная, а клиенту нужен простой вход
Хотите уменьшить связанность между слоями
Типичный пример: сервисный слой в Spring-приложении

▪️ Минус

Фасад может стать God Object, если взять на себя слишком много логики.

🐸 Библиотека собеса по Java

#patterns
Please open Telegram to view this post
VIEW IN TELEGRAM
👍8🔥2🤔2
Расскажите о паттерне Proxy

Proxy — это структурный паттерн, который подставляет вместо реального объекта объект-заместитель, контролирующий доступ к оригиналу.

Простыми словами: прокси выглядит как оригинал, но перед вызовом может проверить права, закэшировать результат или создать объект лениво.

▪️ Пример:

Сервис загрузки документов: реальная загрузка — тяжёлая операция. Прокси проверяет права доступа и кэширует результат.

interface DocumentService {
String loadDocument(String docId);
}

// Реальный сервис — тяжёлая операция
class RealDocumentService implements DocumentService {
public String loadDocument(String docId) {
System.out.println("Загрузка из хранилища: " + docId);
return "Содержимое документа " + docId;
}
}

// Прокси — контроль доступа + кэширование
class DocumentServiceProxy implements DocumentService {
private final RealDocumentService realService = new RealDocumentService();
private final Map<String, String> cache = new HashMap<>();
private final Set<String> allowedRoles;

public DocumentServiceProxy(Set<String> allowedRoles) {
this.allowedRoles = allowedRoles;
}

public String loadDocument(String docId) {
// 1. Проверка доступа
String currentRole = SecurityContext.getCurrentRole();
if (!allowedRoles.contains(currentRole)) {
throw new SecurityException("Нет доступа");
}

// 2. Кэширование
return cache.computeIfAbsent(docId, realService::loadDocument);
}
}

// Клиент работает с прокси как с оригиналом
DocumentService service = new DocumentServiceProxy(Set.of("ADMIN", "EDITOR"));
String doc = service.loadDocument("report-2026");


▪️ Виды прокси

Protection Proxy — контроль доступа (Spring Security)
Caching Proxy — кэширование результатов
Lazy Proxy — отложенная инициализация (Hibernate lazy loading)
Remote Proxy — доступ к удалённому объекту (RMI)

▪️ Proxy vs Decorator

— Proxy: контролирует жизненный цикл и доступ к объекту
— Decorator: добавляет поведение, не контролируя доступ

▪️ Минус

Увеличивает задержку отклика; усложняет отладку при нескольких слоях проксирования.

🐸 Библиотека собеса по Java

#patterns
Please open Telegram to view this post
VIEW IN TELEGRAM
👍5🔥1
Расскажите о паттерне Observer

Observer — это поведенческий паттерн, который создаёт механизм подписки, позволяя одним объектам следить за изменениями в других.

Простыми словами: как подписка на Telegram-канал — когда выходит новый пост, все подписчики получают уведомление автоматически.

▪️ Пример:

Сервис обработки заказов: при смене статуса нужно уведомить склад, аналитику и клиента. Вместо жёстких вызовов — подписка.

// Событие
record OrderEvent(String orderId, String status) {}

// Подписчик
interface OrderListener {
void onOrderStatusChanged(OrderEvent event);
}

// Издатель
class OrderService {
private final List<OrderListener> listeners = new ArrayList<>();

public void subscribe(OrderListener listener) {
listeners.add(listener);
}

public void changeStatus(String orderId, String newStatus) {
// бизнес-логика...
OrderEvent event = new OrderEvent(orderId, newStatus);
listeners.forEach(l -> l.onOrderStatusChanged(event));
}
}

// Конкретные подписчики
class WarehouseListener implements OrderListener {
public void onOrderStatusChanged(OrderEvent event) {
if ("PAID".equals(event.status())) {
System.out.println("Склад: начать сборку " + event.orderId());
}
}
}

class AnalyticsListener implements OrderListener {
public void onOrderStatusChanged(OrderEvent event) {
System.out.println("Аналитика: статус " + event.status());
}
}

// Использование
OrderService service = new OrderService();
service.subscribe(new WarehouseListener());
service.subscribe(new AnalyticsListener());

service.changeStatus("ORD-42", "PAID");
// Склад: начать сборку ORD-42
// Аналитика: статус PAID


▪️ Когда использовать

Изменение одного объекта требует обновления других, и набор зависимых объектов заранее неизвестен
Хотите избежать жёсткой связи между компонентами
В Spring: ApplicationEventPublisher — встроенный Observer

▪️ Минус

Подписчики оповещаются в непредсказуемом порядке; утечки памяти, если забыть отписаться.

🐸 Библиотека собеса по Java

#patterns
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥5👍2🤔1
Расскажите о паттерне Command

Command — это поведенческий паттерн, который превращает запрос в отдельный объект, содержащий всю информацию о запросе.

Простыми словами: вместо прямого вызова метода вы создаёте объект-команду, которую можно передать, поставить в очередь, отменить или повторить.

▪️ Пример:

Текстовый редактор с поддержкой undo/redo: каждое действие — объект, который можно откатить.

// Команда
interface Command {
void execute();
void undo();
}

// Получатель
class TextEditor {
private StringBuilder text = new StringBuilder();

public void insert(int pos, String str) {
text.insert(pos, str);
}

public void delete(int pos, int length) {
text.delete(pos, pos + length);
}

public String getText() { return text.toString(); }
}

// Конкретная команда
class InsertCommand implements Command {
private final TextEditor editor;
private final int position;
private final String text;

public InsertCommand(TextEditor editor, int position, String text) {
this.editor = editor;
this.position = position;
this.text = text;
}

public void execute() {
editor.insert(position, text);
}

public void undo() {
editor.delete(position, text.length());
}
}

// Инвокер с историей
class CommandHistory {
private final Deque<Command> history = new ArrayDeque<>();

public void execute(Command cmd) {
cmd.execute();
history.push(cmd);
}

public void undo() {
if (!history.isEmpty()) {
history.pop().undo();
}
}
}

// Использование
TextEditor editor = new TextEditor();
CommandHistory history = new CommandHistory();

history.execute(new InsertCommand(editor, 0, "Hello"));
history.execute(new InsertCommand(editor, 5, " World"));
System.out.println(editor.getText()); // Hello World

history.undo();
System.out.println(editor.getText()); // Hello


▪️ Когда использовать

Нужен undo/redo
Команды нужно ставить в очередь, логировать или выполнять отложенно
Хотите отделить объект, инициирующий операцию, от объекта, выполняющего её

▪️ Минус

Усложняет код: каждая операция — отдельный класс.

🐸 Библиотека собеса по Java

#patterns
Please open Telegram to view this post
VIEW IN TELEGRAM
5👍3🔥1
Расскажите о паттерне Template Method

Template Method — это поведенческий паттерн, который определяет скелет алгоритма в суперклассе, а подклассы переопределяют конкретные шаги, не меняя общую структуру.

Простыми словами: рецепт борща одинаков (порезать → сварить → подать), но ингредиенты у каждого свои.

▪️ Пример:

Генератор отчётов: шаги одинаковые (загрузить данные → обработать → отформатировать → отправить), но формат вывода — PDF, Excel, HTML — разный.

// Абстрактный класс с шаблонным методом
abstract class ReportGenerator {

// Template Method — final, чтобы подклассы не меняли порядок
public final void generateReport() {
List<Map<String, Object>> data = fetchData();
List<Map<String, Object>> processed = processData(data);
String output = format(processed);
send(output);
}

// Общий шаг
private List<Map<String, Object>> fetchData() {
System.out.println("Загрузка из БД...");
return List.of(Map.of("revenue", 1_000_000));
}

// Общий шаг с возможностью расширения
protected List<Map<String, Object>> processData(
List<Map<String, Object>> data) {
return data; // по умолчанию — без обработки
}

// Абстрактный шаг — подклассы обязаны реализовать
protected abstract String format(List<Map<String, Object>> data);

// Hook — подклассы могут переопределить
protected void send(String output) {
System.out.println("Отправка по email: " + output.substring(0, 50));
}
}

class PdfReportGenerator extends ReportGenerator {
protected String format(List<Map<String, Object>> data) {
return "PDF: " + data.toString();
}
}

class ExcelReportGenerator extends ReportGenerator {
protected String format(List<Map<String, Object>> data) {
return "XLSX: " + data.toString();
}

@Override
protected void send(String output) {
System.out.println("Загрузка в Google Drive: " + output.substring(0, 50));
}
}

// Использование
new PdfReportGenerator().generateReport();
new ExcelReportGenerator().generateReport();


▪️ Когда использовать

Алгоритм одинаков по структуре, но шаги различаются
Хотите избежать дублирования кода между похожими классами
В Spring: JdbcTemplate, RestTemplate — классические примеры

▪️ Template Method vs Strategy

— Template Method: наследование, подклассы переопределяют шаги
— Strategy: композиция, алгоритм передаётся извне

▪️ Минус

Жёсткая привязка к наследованию; нарушается LSP, если подклассы ломают контракт шагов.

🐸 Библиотека собеса по Java

#patterns
Please open Telegram to view this post
VIEW IN TELEGRAM
👍7🔥2👏2