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

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

رفتن به کانال در Telegram

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

نمایش بیشتر
6 485
مشترکین
+124 ساعت
+87 روز
+1330 روز
آرشیو پست ها
Расскажите о паттерне 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

Расскажите о паттерне 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

💬 Обратная связь Как часто вы проходите собеседования? 🔥 — Сейчас активно ищу работу 👍🏼 — Раз в несколько месяцев ❤️ — Раз в полгода-год 😁 — Не прохожу, уже работаю/ещё учусь 🐸 Библиотека собеса по Java

✔️ Java-тест: объект в HashSet есть, но contains() возвращает false Добавили объект в Set. Он там. Но найти его невозможно. Утечка памяти в проде. Почему? 📦 Задание — code review Команда хранит активные сессии в HashSet. После смены роли пользователя сессия «пропадает» из множества — contains() возвращает false, remove() не удаляет. Set растёт, память течёт.
public class UserSession {
    private Long userId;
    private String role;

    public UserSession(Long userId, String role) {
        this.userId = userId;
        this.role = role;
    }

    // getters, setters

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        UserSession that = (UserSession) o;
        return Objects.equals(userId, that.userId)
            && Objects.equals(role, that.role);
    }

    @Override
    public int hashCode() {
        return Objects.hash(userId, role);
    }
}

@Service
public class SessionManager {

    private final Set<UserSession> activeSessions = new HashSet<>();

    public void addSession(UserSession session) {
        activeSessions.add(session);
    }

    public void promoteToAdmin(Long userId) {
        activeSessions.stream()
            .filter(s -> s.getUserId().equals(userId))
            .findFirst()
            .ifPresent(s -> s.setRole("ADMIN"));
    }

    public boolean isActive(UserSession session) {
        return activeSessions.contains(session);
    }

    public void removeSession(UserSession session) {
        activeSessions.remove(session);
    }
}
// Сценарий бага:
sessionManager.addSession(new UserSession(1L, "USER"));   // ОК
sessionManager.promoteToAdmin(1L);                         // меняем роль
sessionManager.isActive(new UserSession(1L, "ADMIN"));     // false ?!
// объект внутри Set есть, но достать его нельзя
▪️ Почему после promoteToAdmin() сессия становится невидимой для contains() и remove()? ▪️ Как исправить, не ломая бизнес-логику? Ставьте → 🔥, если нравится формат. Если нет → 🌚 💬 Решения под спойлер. Сравним, какое будет лучше. 🐸 Библиотека собеса по Java #practise

Расскажите о паттерне 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

Расскажите о паттерне 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

Расскажите о паттерне 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

🔥 Знакомьтесь с экспертом Proglib.academy: Эмиль Сатаев Эмиль — эксперт с 8-летним опытом в разработке, который специализиру
🔥 Знакомьтесь с экспертом Proglib.academy: Эмиль Сатаев Эмиль — эксперт с 8-летним опытом в разработке, который специализируется на внедрении LLM и агентных подходов в реальные коммерческие сервисы. Он точно знает, как проектировать архитектуру так, чтобы ИИ-функции работали стабильно в связке с внешними системами. 🏃‍♀️ Уже 14 мая Эмиль проведет открытый вебинар! Обсудим самую «больную» тему: «Почему AI-продукты на базе LLM ломаются и как сделать, чтобы работало». 🗓 Когда: 14 мая в 19:00 (Мск) Почему Эмиля стоит послушать: 🟣 8+ лет в разработке (Backend и Frontend)
Прошел путь от фулстека до Backend Platform Developer в SMIT.Studio.
🟣 Международный исследовательский опыт
Работал исследователем в Институте ИИ НИУ ВШЭ и в Национальном университете Сингапура (NUS).
🟣 Преподаватель-практик
Ведет семинары в НИУ ВШЭ, в том числе по проектированию и разработке агентских систем.
🟣 Мастер интеграции AI в Backend
Его главная суперсила — умение правильно встраивать LLM через API, выстраивать workflow и агентную логику в сложных распределенных системах.
🔗 Зарегистрироваться на вебинар

Расскажите о паттерне 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

Расскажите о паттерне 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

🗓 14 мая в 19:00 (Мск) встречаемся в онлайне. Тема: Почему AI-продукты на базе LLM ломаются и как сделать, чтобы работало. В кружке выше Эмиль Сатаев рассказал, какие именно проблемы с LLM в проде будем разбирать. Что в программе:
- Разберем реальные кейсы стартапов и ограничения LLM. - Обсудим рабочие архитектуры: RAG, human-in-the-loop, контроль качества. - Ответим на ваши вопросы и разберем кейсы участников.
🎁 Бонусы: в конце вебинара подарим промокод на скидку 10.000 ₽ на курсы и разыграем подписки на полезные AI-сервисы. 👉 Зарегистрироваться на вебинар

Расскажите о паттерне 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

✔️ Java-тест: транзакция, которая не откатывается @Transactional стоит, исключение летит. Данные в БД остаются. Почему? 📦 Задание — code review Команда добавила транзакцию на метод сохранения заказа. При ошибке валидации данные всё равно коммитятся в базу. @Transactional на месте, но не работает.
public class CheckedBusinessException extends Exception {
    public CheckedBusinessException(String message) {
        super(message);
    }
}

@Service
public class OrderService {

    private final OrderRepository orderRepository;
    private final InventoryService inventoryService;

    @Transactional
    public void placeOrder(Order order) throws CheckedBusinessException {
        orderRepository.save(order);
        inventoryService.reserveStock(order);
    }
}

@Service
public class InventoryService {

    public void reserveStock(Order order) throws CheckedBusinessException {
        if (order.getQuantity() > availableStock) {
            throw new CheckedBusinessException("Not enough stock");
        }
    }
}
▪️ Почему @Transactional не откатывает изменения при CheckedBusinessException? ▪️ Как добиться rollback в этом коде Ставьте → 🔥, если нравится формат. Если нет → 🌚 💬 Решения под спойлер. Сравним, какое будет лучше. 🐸 Библиотека собеса по Java #practise

🦾 Почему ваши AI-продукты на базе LLM ломаются (и как это чинить)? Выкатили ИИ-фичу в прод, а она галлюцинирует, падает или
🦾 Почему ваши AI-продукты на базе LLM ломаются (и как это чинить)? Выкатили ИИ-фичу в прод, а она галлюцинирует, падает или выдает мусор? Приглашаем на открытый вебинар, где разберем реальную боль внедрения LLM-агентов и научимся делать так, чтобы «всё работало». 🗓 Когда: 14 мая в 19:00 МСК ⏱️ Формат: 60 минут мяса + 30 минут ответов на ваши вопросы 🧑🏻‍💻 Кто вещает: Эмиль Сатаев — Backend Platform Developer (8+ лет в разработке). Человек, который своими руками внедряет LLM и агентные системы в реальные коммерческие сервисы. 🎁 Главный бонус для онлайна: Только участникам прямого эфира подарим уникальный промокод на скидку 10.000 ₽ на большой курс AgentOps. 👉 Занять место на вебинаре

Расскажите о паттерне 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

Расскажите о паттерне Factory Method Factory Method — порождающий паттерн, который определяет общий интерфейс для создания объектов в суперклассе, позволяя подклассам изменять тип создаваемых объектов. 🔹 Когда использовать: Когда заранее неизвестны типы и зависимости объектов, или когда нужно делегировать создание объектов подклассам. 🔹 Как работает: Создается абстрактный метод для создания объектов, а конкретные подклассы переопределяют его, возвращая нужные типы. 🔹 Плюсы:избавляет от привязки к конкретным классам;упрощает добавление новых типов продуктов;следует Open/Closed Principle. 🐸 Библиотека собеса по Java #patterns

Расскажите о паттерне Adapter Adapter (Адаптер) — это структурный паттерн проектирования, который позволяет объектам с несовместимыми интерфейсами работать вместе. Он выступает в роли "переходника" между двумя интерфейсами. 🔹 Когда использовать: Когда нужно использовать существующий класс, но его интерфейс не соответствует требуемому. Например, при интеграции сторонних библиотек или работе с легаси-кодом. 🐸 Библиотека собеса по Java #patterns

Расскажите о паттерне Singleton? Singleton — это порождающий паттерн проектирования, который гарантирует, что у класса существует только один экземпляр, и предоставляет глобальную точку доступа к нему. 🔹 Основные характеристики:приватный конструктор запрещает создание экземпляров извне;статический метод getInstance() возвращает единственный экземпляр;статическое поле для хранения экземпляра. 🔹 Когда использовать:объект содержит глобальное состояние;создание объекта ресурсозатратно;нужен единый координатор действий;логически должен быть один экземпляр. 🐸 Библиотека собеса по Java #patterns

Расскажите о паттерне Strategy? Strategy — это поведенческий паттерн, который позволяет определить семейство алгоритмов, инкапсулировать каждый из них и сделать их взаимозаменяемыми. Когда использовать:есть несколько способов выполнения одной операции;нужно избежать множественных if-else или switch;алгоритмы должны выбираться в runtime. Преимущества: соблюдение Open/Closed Principle, устранение условных операторов, гибкость выбора алгоритма. 🐸 Библиотека собеса по Java #patterns