Ответ
В своей практике я чаще всего применяю следующие паттерны, разделяя их по целям:
Порождающие (Creational):
- Фабричный метод (Factory Method) / Абстрактная фабрика (Abstract Factory): Использовал для создания семейств связанных объектов, например, различных провайдеров аутентификации (OAuth, JWT, LDAP) или парсеров разных форматов логов (JSON, XML, CSV). Это позволяет изолировать логику создания.
- Строитель (Builder): Применял для пошагового конструирования сложных объектов конфигурации или DTO с множеством необязательных полей, что делает код чище, чем вызов конструктора с десятком параметров.
- Внедрение зависимостей (Dependency Injection): Основа большинства современных фреймворков. Активно использую для повышения тестируемости и уменьшения связности компонентов.
Структурные (Structural):
- Адаптер (Adapter): Интегрировал сторонние библиотеки или legacy-код, создавая класс-обертку с нужным интерфейсом.
- Декоратор (Decorator): Использовал для динамического добавления функциональности, например, добавления логирования, кэширования или проверки прав доступа к основному сервису без изменения его кода.
- Фасад (Facade): Создавал упрощенные интерфейсы для работы со сложными подсистемами (например, модулем отчетности или интеграцией с внешним API).
Поведенческие (Behavioral):
- Стратегия (Strategy): Применял для инкапсуляции алгоритмов, которые могут меняться (например, алгоритмы сортировки, стратегии расчета скидок или способы отправки уведомлений — email, SMS, push). Это позволяет легко подменять их в runtime.
- Наблюдатель (Observer): Реализовывал для построения систем событий (event-driven). Например, при изменении статуса заказа автоматически запускались обработчики для отправки уведомления клиенту, обновления склада и логирования.
- Команда (Command): Использовал для инкапсуляции запросов как объектов, что полезно для реализации очереди задач, отмены операций (undo/redo) или отложенного выполнения.
Пример Стратегии на Java для валидации:
// Интерфейс стратегии
interface ValidationStrategy {
boolean execute(String data);
}
// Конкретные стратегии
class EmailValidation implements ValidationStrategy {
public boolean execute(String data) {
return data.matches("^[^@]+@[^@]+\.[^@]+$");
}
}
class PhoneValidation implements ValidationStrategy {
public boolean execute(String data) {
return data.matches("^\+?[0-9]{10,}$");
}
}
// Контекст, использующий стратегию
class Validator {
private ValidationStrategy strategy;
public Validator(ValidationStrategy strategy) {
this.strategy = strategy;
}
public boolean validate(String input) {
return strategy.execute(input);
}
}
// Использование
Validator emailValidator = new Validator(new EmailValidation());
boolean isValid = emailValidator.validate("test@example.com");
Ключевой принцип — не использовать паттерны ради самих паттернов, а применять их для решения конкретных проблем проектирования, таких как снижение связанности, повышение гибкости или улучшение тестируемости кода.
Видео-ответы
▶
▶
▶
▶
▶
▶
▶
▶
▶
▶
▶
▶
▶
▶
▶
▶
▶
▶
▶
▶
▶
▶
▶
▶
▶