uz
Feedback
Библиотека собеса по Java | вопросы с собеседований

Библиотека собеса по Java | вопросы с собеседований

Kanalga Telegram’da o‘tish

Вопросы с собеседований по Java и ответы на них. По рекламе: @proglib_adv Учиться у нас: https://proglib.io/w/08c603b6 Для обратной связи: @proglibrary_feeedback_bot

Ko'proq ko'rsatish
6 482
Obunachilar
+124 soatlar
+87 kunlar
+1330 kunlar
Obunachilarni jalb qilish
Iyun '26
Iyun '26
+9
0 kanalda
May '26
+83
3 kanalda
Get PRO
Aprel '26
+87
2 kanalda
Get PRO
Mart '26
+81
2 kanalda
Get PRO
Fevral '26
+121
4 kanalda
Get PRO
Yanvar '26
+93
1 kanalda
Get PRO
Dekabr '25
+96
5 kanalda
Get PRO
Noyabr '25
+112
2 kanalda
Get PRO
Oktabr '25
+94
1 kanalda
Get PRO
Sentabr '25
+95
1 kanalda
Get PRO
Avgust '25
+78
3 kanalda
Get PRO
Iyul '25
+98
0 kanalda
Get PRO
Iyun '25
+70
0 kanalda
Get PRO
May '25
+78
0 kanalda
Get PRO
Aprel '25
+133
1 kanalda
Get PRO
Mart '25
+283
52 kanalda
Get PRO
Fevral '25
+176
31 kanalda
Get PRO
Yanvar '25
+207
35 kanalda
Get PRO
Dekabr '24
+179
35 kanalda
Get PRO
Noyabr '24
+326
37 kanalda
Get PRO
Oktabr '24
+284
35 kanalda
Get PRO
Sentabr '24
+299
35 kanalda
Get PRO
Avgust '24
+289
35 kanalda
Get PRO
Iyul '24
+275
35 kanalda
Get PRO
Iyun '24
+272
31 kanalda
Get PRO
May '24
+429
37 kanalda
Get PRO
Aprel '24
+474
37 kanalda
Get PRO
Mart '24
+299
29 kanalda
Get PRO
Fevral '24
+373
29 kanalda
Get PRO
Yanvar '24
+392
24 kanalda
Get PRO
Dekabr '23
+900
26 kanalda
Get PRO
Noyabr '23
+229
3 kanalda
Get PRO
Oktabr '23
+369
22 kanalda
Get PRO
Sentabr '23
+1 761
0 kanalda
Sana
Obunachilarni jalb qilish
Esdaliklar
Kanallar
03 Iyun+5
02 Iyun+1
01 Iyun+3
Kanal postlari
Возможна ли утечка памяти, несмотря на сборщик мусора? Да, возможна. GC удаляет только недостижимые объекты. Утечка — это когда объекты остаются достижимыми, но больше не нужны, и память не освобождается. Типичные источники:неограниченные кеши и статические коллекции (static Map), которые растут без удаления;незакрытые ресурсы (соединения, стримы);слушатели/колбэки без отписки; ThreadLocal в пуле потоков, где значение не очищается через remove() (поток переиспользуется и не умирает);утечка класслоадеров при горячей перезагрузке. 🐸 Библиотека собеса по Java #core

2
❓ Что такое escape analysis и какие оптимизации он даёт? Это анализ JIT-компилятора, который определяет, «убегает» ли объект за пределы метода или потока. Если объект создаётся и используется только локально и наружу не уходит, JVM может: → Scalar replacement — вообще не создавать объект в куче, а разложить его на отдельные поля в регистрах/на стеке. Это снимает нагрузку на GC. → Lock elision — убрать синхронизацию, если объект гарантированно не виден другим потокам. 🐸 Библиотека собеса по Java #jvm
562
3
❓ Что происходит с объектом, когда на него не осталось ссылок? Объект становится кандидатом на сборку мусора, но память освобождается не сразу. GC ориентируется на достижимость от GC roots (стек потоков, статические поля, JNI-ссылки, активные локальные переменные). Пока объект достижим хотя бы по одной цепочке — он живой. Как только он перестаёт быть достижимым, он помечается недостижимым и память освобождается при ближайшем цикле сборки. Если у объекта есть finalize() или он зарегистрирован в Cleaner/PhantomReference, освобождение откладывается на дополнительный цикл. 🐸 Библиотека собеса по Java #core
636
4
💬 Обратная связь Текущий уровень сложности вопросов? 🔥 — Слишком просто, хочу сложнее 👍🏼 — В самый раз ❤️ — Иногда сложновато 😁 — Часто не понимаю 🐸 Библиотека собеса по Java
666
5
❓ Расскажите о паттерне Interpreter Interpreter — это поведенческий паттерн, который определяет грамматику простого языка и интерпретатор для его предложений. Простыми словами: вы описываете правила «мини-языка» в виде классов, и каждый класс умеет вычислить свою часть выражения. Как калькулятор, который разбирает «3 + 5 * 2». ▪️ Пример: Движок фильтрации пользователей по правилам: «возраст > 18 AND город = Москва». Каждое условие — узел дерева выражений. // Абстрактное выражение interface Expression { boolean interpret(Map<String, String> context); } // Терминальное выражение — проверка одного поля class Equals implements Expression { private final String key; private final String value; public Equals(String key, String value) { this.key = key; this.value = value; } public boolean interpret(Map<String, String> context) { return value.equals(context.get(key)); } } class GreaterThan implements Expression { private final String key; private final int threshold; public GreaterThan(String key, int threshold) { this.key = key; this.threshold = threshold; } public boolean interpret(Map<String, String> context) { return Integer.parseInt(context.getOrDefault(key, "0")) > threshold; } } // Нетерминальные выражения — комбинаторы class And implements Expression { private final Expression left, right; public And(Expression left, Expression right) { this.left = left; this.right = right; } public boolean interpret(Map<String, String> context) { return left.interpret(context) && right.interpret(context); } } class Or implements Expression { private final Expression left, right; public Or(Expression left, Expression right) { this.left = left; this.right = right; } public boolean interpret(Map<String, String> context) { return left.interpret(context) || right.interpret(context); } } // Использование: возраст > 18 AND город = Москва Expression rule = new And( new GreaterThan("age", 18), new Equals("city", "Москва") ); Map<String, String> user1 = Map.of("age", "25", "city", "Москва"); Map<String, String> user2 = Map.of("age", "16", "city", "Москва"); System.out.println(rule.interpret(user1)); // true System.out.println(rule.interpret(user2)); // false ▪️ Когда использовать — Есть простой язык или набор правил, которые нужно интерпретировать — Грамматика стабильна, но выражений — много — Пример: SpEL (Spring Expression Language), регулярные выражения ▪️ Минус Для сложных грамматик дерево классов разрастается и становится неуправляемым — лучше использовать парсер-генераторы (ANTLR). 🐸 Библиотека собеса по Java #patterns
687
6
❓ Расскажите о паттерне Visitor Visitor — это поведенческий паттерн, который позволяет добавлять новые операции к объектам, не изменяя их классы. Простыми словами: налоговый инспектор (visitor) приходит в разные компании и выполняет проверку — компании не меняются, а новые виды проверок добавляются легко. ▪️ Пример: Система документооборота: есть разные типы документов, и нужно добавлять операции (экспорт, валидация, подсчёт статистики) без изменения классов документов. // Visitor interface DocumentVisitor { void visit(Invoice invoice); void visit(Contract contract); void visit(Report report); } // Элементы interface Document { void accept(DocumentVisitor visitor); } class Invoice implements Document { private final BigDecimal amount; public Invoice(BigDecimal amount) { this.amount = amount; } public BigDecimal getAmount() { return amount; } public void accept(DocumentVisitor visitor) { visitor.visit(this); // double dispatch } } class Contract implements Document { private final LocalDate expiryDate; public Contract(LocalDate expiryDate) { this.expiryDate = expiryDate; } public LocalDate getExpiryDate() { return expiryDate; } public void accept(DocumentVisitor visitor) { visitor.visit(this); } } class Report implements Document { private final int pageCount; public Report(int pageCount) { this.pageCount = pageCount; } public int getPageCount() { return pageCount; } public void accept(DocumentVisitor visitor) { visitor.visit(this); } } // Конкретный visitor — новая операция без изменения документов class ExportVisitor implements DocumentVisitor { public void visit(Invoice invoice) { System.out.println("Экспорт счёта: " + invoice.getAmount() + " ₽"); } public void visit(Contract contract) { System.out.println("Экспорт договора до " + contract.getExpiryDate()); } public void visit(Report report) { System.out.println("Экспорт отчёта: " + report.getPageCount() + " стр."); } } // Использование List<Document> docs = List.of( new Invoice(new BigDecimal("150000")), new Contract(LocalDate.of(2027, 1, 1)), new Report(42) ); DocumentVisitor exporter = new ExportVisitor(); docs.forEach(doc -> doc.accept(exporter)); ▪️ Когда использовать — Нужно выполнить операцию над группой разнородных объектов — Новые операции добавляются часто, а новые типы элементов — редко — Пример из JDK: java.nio.file.FileVisitor ▪️ Минус Visitor нужно обновлять при добавлении нового типа элемента — нарушается Open/Closed Principle для элементов. 🐸 Библиотека собеса по Java #patterns
1 804
7
До 31 мая можно забрать любой курс Proglib Academy со скидкой 40% Если давно хотели прокачаться в Python, ML, алгоритмах или
До 31 мая можно забрать любой курс Proglib Academy со скидкой 40% Если давно хотели прокачаться в Python, ML, алгоритмах или AI-агентах, сейчас самое время выбрать программу и начать обучение по сниженной цене. 🎁 Разработка AI-агентов — от 49.000 ₽ (вместо 69.000 ₽) Практический курс по разработке AI-агентов для автоматизации задач, работы и собственных проектов 🎁 Курс AgentOps — 129.000 ₽ (вместо 149.000 ₽) Для разработчиков и LLM-инженеров, которые хотят внедрять AI-логику в бэкенд и сохранять стабильность сервиса. 🎁 Математика для разработки AI-моделей — 23.990 ₽ (вместо 31.990 ₽) Практическая база по математике для анализа данных, ML и дальнейшего развития в AI. 🎁 Математика для Data Science — от 29.990 ₽ (вместо 39.990 ₽) Курс для тех, кто хочет решать задачи, которые дают на собеседованиях на позицию дата-сайентиста в бигтехе. 🎁 ML для старта в Data Science — 28.990 ₽ (вместо 38.990 ₽) Разберётесь в машинном обучении: от базовых понятий и линейных моделей до ансамблей, бустинга и рекомендательных систем. 🎁 Основы IT для непрограммистов — 16.990 ₽ (вместо 28.990 ₽) Курс для IT-рекрутеров, маркетологов, проджектов, продактов и всех, кто работает с IT, но не пишет код. 🎁 Архитектуры и шаблоны проектирования — 27.990 ₽ (вместо 37.900 ₽) Освоите основные паттерны проектирования и прокачаете навыки архитектора программного обеспечения. 🎁 Специалист по ИИ — 89.000 ₽ (вместо 113.900 ₽) Курс для тех, кто хочет получить профессию в сфере ИИ, собрать портфолио из 5 проектов и научиться разрабатывать сложных AI-агентов. 🎁 Алгоритмы и структуры данных — 33.990 ₽ (вместо 57.990 ₽) Подготовитесь к алгоритмическим собеседованиям, разберёте структуры данных и научитесь писать более эффективный код. 🎁 Программирование на языке Python — 27.990 ₽ (вместо 47.390 ₽) Освоите Python на практике: без сухой теории, с пошаговой прокачкой навыков и итоговым проектом в портфолио. 🙌 Выбирайте курс по ссылке, оставляйте заявку, и менеджер поможет подобрать программу под ваши цели — https://clc.to/SALE40
528
8
❓ Расскажите о паттерне Memento Memento — это поведенческий паттерн, который позволяет сохранять и восстанавливать прежнее состояние объекта, не нарушая инкапсуляцию. Простыми словами: Ctrl+Z в любом редакторе — где-то хранится снимок предыдущего состояния, к которому можно откатиться. ▪️ Пример: Редактор конфигурации сервера: администратор меняет настройки и может откатиться к любой предыдущей версии. // Memento — снимок состояния (immutable) record ConfigMemento( Map<String, String> properties, LocalDateTime timestamp ) { public ConfigMemento { properties = Map.copyOf(properties); // защитная копия } } // Originator — объект, чьё состояние сохраняем class ServerConfig { private final Map<String, String> properties = new HashMap<>(); public void set(String key, String value) { properties.put(key, value); } public String get(String key) { return properties.get(key); } public ConfigMemento save() { return new ConfigMemento(properties, LocalDateTime.now()); } public void restore(ConfigMemento memento) { properties.clear(); properties.putAll(memento.properties()); } } // Caretaker — хранит историю снимков class ConfigHistory { private final Deque<ConfigMemento> snapshots = new ArrayDeque<>(); public void backup(ServerConfig config) { snapshots.push(config.save()); } public void undo(ServerConfig config) { if (!snapshots.isEmpty()) { config.restore(snapshots.pop()); } } } // Использование ServerConfig config = new ServerConfig(); ConfigHistory history = new ConfigHistory(); config.set("maxThreads", "200"); history.backup(config); config.set("maxThreads", "500"); config.set("timeout", "30s"); history.backup(config); config.set("maxThreads", "1"); // ой, ошибка history.undo(config); System.out.println(config.get("maxThreads")); // 500 ▪️ Когда использовать — Нужна функция отмены/отката (undo) — Нужно сохранять контрольные точки состояния — Прямой доступ к полям объекта нарушил бы инкапсуляцию ▪️ Memento vs Command — Command: хранит действие и умеет его отменить — Memento: хранит полный снимок состояния ▪️ Минус Может потреблять много памяти, если состояние объекта большое и снимки создаются часто. 🐸 Библиотека собеса по Java #patterns
610
9
Перед вами классическая визуализация одного из методов сортировки. как считаете, какой это метод? 👍— Сортировка выбором (Sel
Перед вами классическая визуализация одного из методов сортировки. как считаете, какой это метод? 👍— Сортировка выбором (Selection Sort) ❤️— Сортировка слиянием (Merge Sort) 🔥— Сортировка пузырьком (Bubble Sort) 🔹 Курс «Алгоритмы и структуры данных» 🔹 Получить консультацию менеджера 🔹 Сайт Академии 🔹 Сайт Proglib 🏃‍♀️ Азбука айтишника #магиякода
686
10
❓ Расскажите о паттерне Mediator Mediator — это поведенческий паттерн, который убирает прямые связи между компонентами, заставляя их общаться через посредника. Простыми словами: диспетчер в аэропорту — самолёты не переговариваются друг с другом, а общаются через башню управления. ▪️ Пример: Чат-комната: пользователи не отправляют сообщения друг другу напрямую — всё идёт через комнату, которая решает, кому доставить. // Медиатор interface ChatRoom { void sendMessage(String message, User sender); void addUser(User user); } class GroupChatRoom implements ChatRoom { private final List<User> users = new ArrayList<>(); public void addUser(User user) { users.add(user); user.setChatRoom(this); } public void sendMessage(String message, User sender) { users.stream() .filter(u -> u != sender) .forEach(u -> u.receive(message, sender.getName())); } } // Коллега class User { private final String name; private ChatRoom chatRoom; public User(String name) { this.name = name; } public void setChatRoom(ChatRoom room) { this.chatRoom = room; } public void send(String message) { chatRoom.sendMessage(message, this); } public void receive(String message, String from) { System.out.println(name + " получил от " + from + ": " + message); } public String getName() { return name; } } // Использование ChatRoom room = new GroupChatRoom(); User alice = new User("Alice"); User bob = new User("Bob"); User carol = new User("Carol"); room.addUser(alice); room.addUser(bob); room.addUser(carol); alice.send("Привет всем!"); // Bob получил от Alice: Привет всем! // Carol получил от Alice: Привет всем! ▪️ Когда использовать — Компоненты слишком сильно связаны друг с другом — Хотите переиспользовать компоненты в других контекстах — Примеры: Spring MVC DispatcherServlet — медиатор между контроллерами ▪️ Минус Медиатор может стать God Object, сконцентрировав слишком много логики. 🐸 Библиотека собеса по Java #patterns
662
11
🔴 Завтра тестовое собеседование с Java-разработчиком 27 мая(уже завтра!) в 19:00 по мск приходи онлайн на открытое собеседов
🔴 Завтра тестовое собеседование с Java-разработчиком 27 мая(уже завтра!) в 19:00 по мск приходи онлайн на открытое собеседование, чтобы посмотреть на настоящее интервью на Middle Java-разработчика. Как это будет: 📂 Сергей Чамкин, старший разработчик из Uzum, ex-WildBerries, будет задавать реальные вопросы и задачи разработчику-добровольцу 📂 Cергей будет комментировать каждый ответ респондента, чтобы дать понять чего от вас ожидает собеседующий на интервью 📂 В конце можно будет задать любой вопрос Сергею Это бесплатно. Эфир проходит в рамках менторской программы от ШОРТКАТ для Java-разработчиков, которые хотят повысить свой грейд, ЗП и прокачать скиллы. Переходи в нашего бота, чтобы получить ссылку на эфир → @shortcut_sh_bot Реклама. О рекламодателе.
666
12
❓ Расскажите о паттерне Iterator Iterator — это поведенческий паттерн, который даёт возможность последовательно обходить элементы коллекции, не раскрывая её внутреннее устройство. Простыми словами: вы проходите по элементам через «окошко» (hasNext / next), не зная — это массив, дерево или база данных за ним. ▪️ Пример: Пагинация по результатам из БД: клиент обходит элементы как обычную коллекцию, а итератор незаметно подгружает следующую страницу. class PaginatedIterator<T> implements Iterator<T> { private final Function<Integer, List<T>> pageFetcher; private final int pageSize; private List<T> currentPage; private int pageIndex = 0; private int itemIndex = 0; public PaginatedIterator(Function<Integer, List<T>> pageFetcher, int pageSize) { this.pageFetcher = pageFetcher; this.pageSize = pageSize; this.currentPage = pageFetcher.apply(0); } public boolean hasNext() { if (itemIndex < currentPage.size()) return true; if (currentPage.size() < pageSize) return false; // последняя страница // Подгружаем следующую страницу pageIndex++; currentPage = pageFetcher.apply(pageIndex); itemIndex = 0; return !currentPage.isEmpty(); } public T next() { if (!hasNext()) throw new NoSuchElementException(); return currentPage.get(itemIndex++); } } // Использование — клиент не знает про пагинацию Iterator<User> users = new PaginatedIterator<>( page -> userRepository.findAll(PageRequest.of(page, 50)).getContent(), 50 ); while (users.hasNext()) { User user = users.next(); // подгрузка происходит автоматически process(user); } ▪️ Когда использовать — Нужен единый способ обхода для разных структур данных — Хотите скрыть сложность обхода (дерево, граф, пагинация) — В Java: все коллекции реализуют Iterable, что позволяет for-each ▪️ Минус Для простых коллекций — избыточен; итератор может устареть при изменении коллекции (ConcurrentModificationException). 🐸 Библиотека собеса по Java #patterns
686
13
❓ Расскажите о паттерне Chain of Responsibility Chain of Responsibility — это поведенческий паттерн, который позволяет передавать запрос по цепочке обработчиков. Каждый обработчик решает: обработать запрос или передать дальше. Простыми словами: как эскалация тикета: L1 → L2 → L3 саппорт. Каждый уровень либо решает проблему, либо передаёт выше. ▪️ Пример: Валидация HTTP-запроса: проверка аутентификации → авторизации → rate limit → бизнес-логика. Каждый шаг — звено цепочки. // Абстрактный обработчик abstract class RequestHandler { private RequestHandler next; public RequestHandler setNext(RequestHandler next) { this.next = next; return next; // для цепочки вызовов } public void handle(HttpRequest request) { if (next != null) { next.handle(request); } } } class AuthenticationHandler extends RequestHandler { public void handle(HttpRequest request) { if (request.getToken() == null) { throw new SecurityException("Нет токена"); } System.out.println("✓ Аутентификация пройдена"); super.handle(request); // передаём дальше } } class RateLimitHandler extends RequestHandler { private final Map<String, Integer> counters = new ConcurrentHashMap<>(); public void handle(HttpRequest request) { int count = counters.merge(request.getIp(), 1, Integer::sum); if (count > 100) { throw new RuntimeException("429 Too Many Requests"); } System.out.println("✓ Rate limit OK"); super.handle(request); } } class BusinessLogicHandler extends RequestHandler { public void handle(HttpRequest request) { System.out.println("✓ Бизнес-логика выполнена"); // конец цепочки } } // Сборка цепочки RequestHandler chain = new AuthenticationHandler(); chain.setNext(new RateLimitHandler()) .setNext(new BusinessLogicHandler()); chain.handle(request); ▪️ Когда использовать — Набор обработчиков и их порядок определяется динамически — Запрос должен быть обработан одним из нескольких объектов, но каким — неизвестно заранее — Классический пример: фильтры в Servlet API (javax.servlet.Filter) ▪️ Минус Запрос может пройти всю цепочку и не быть обработанным; сложно отладить длинную цепочку. 🐸 Библиотека собеса по Java #patterns
689
14
💬 Обратная связь Последние посты все по единой теме паттернов. Удобно ли, если посты будут иногда такими едиными блоками? 🔥 — Удобно 👍🏼 — Без разницы 😁 — Скука смертная, хочется разнообразия 🐸 Библиотека собеса по Java
822
15
❓ Расскажите о паттерне State State — это поведенческий паттерн, который позволяет объекту менять своё поведение при изменении внутреннего состояния. Извне кажется, что объект сменил свой класс. Простыми словами: банкомат ведёт себя по-разному в зависимости от состояния: ожидание карты → ввод PIN → выбор операции. Одна и та же кнопка делает разные вещи. ▪️ Пример: Заказ в интернет-магазине проходит через состояния: Новый → Оплачен → Доставляется → Завершён. В каждом состоянии допустимы разные действия. // Интерфейс состояния interface OrderState { void pay(OrderContext order); void ship(OrderContext order); void deliver(OrderContext order); } // Контекст class OrderContext { private OrderState state; public OrderContext() { this.state = new NewOrderState(); } public void setState(OrderState state) { this.state = state; System.out.println("Статус → " + state.getClass().getSimpleName()); } public void pay() { state.pay(this); } public void ship() { state.ship(this); } public void deliver() { state.deliver(this); } } class NewOrderState implements OrderState { public void pay(OrderContext order) { System.out.println("Оплата принята"); order.setState(new PaidOrderState()); } public void ship(OrderContext order) { System.out.println("Нельзя отправить неоплаченный заказ"); } public void deliver(OrderContext order) { System.out.println("Заказ ещё не отправлен"); } } class PaidOrderState implements OrderState { public void pay(OrderContext order) { System.out.println("Уже оплачен"); } public void ship(OrderContext order) { System.out.println("Заказ передан курьеру"); order.setState(new ShippedOrderState()); } public void deliver(OrderContext order) { System.out.println("Заказ ещё не отправлен"); } } class ShippedOrderState implements OrderState { public void pay(OrderContext order) { System.out.println("Уже оплачен"); } public void ship(OrderContext order) { System.out.println("Уже в пути"); } public void deliver(OrderContext order) { System.out.println("Заказ доставлен!"); order.setState(new DeliveredOrderState()); } } class DeliveredOrderState implements OrderState { public void pay(OrderContext o) { System.out.println("Завершён"); } public void ship(OrderContext o) { System.out.println("Завершён"); } public void deliver(OrderContext o) { System.out.println("Уже доставлен"); } } // Использование OrderContext order = new OrderContext(); order.pay(); // Оплата принята → PaidOrderState order.ship(); // Передан курьеру → ShippedOrderState order.deliver(); // Доставлен! → DeliveredOrderState order.pay(); // Завершён ▪️ Когда использовать — Объект ведёт себя по-разному в зависимости от состояния — Много if/switch по статусу — признак, что нужен State — Количество состояний может расти ▪️ State vs Strategy — Strategy: клиент выбирает алгоритм — State: объект сам переключает поведение при смене состояния ▪️ Минус Избыточен, если состояний всего 2–3 и переходы простые. 🐸 Библиотека собеса по Java #patterns
906
16
❓ Расскажите о паттерне 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
851
17
❓ Расскажите о паттерне 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
855
18
❓ Расскажите о паттерне 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
850
19
❓ Расскажите о паттерне 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
981
20
❓ Расскажите о паттерне 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
1 007