Какие паттерны знаешь кроме Singleton и Factory
Комментарии (1)
Ответ сгенерирован нейросетью и может содержать ошибки
Design Patterns в Java
Кроме Singleton и Factory существует множество полезных паттернов проектирования, разделённых на три основные категории. Рассмотрю наиболее практичные для backend-разработки.
Порождающие паттерны (Creational)
Builder
Builder упрощает создание сложных объектов с множеством параметров:
public class User {
private String name;
private String email;
private int age;
private String phone;
public static class Builder {
private String name;
private String email;
private int age;
private String phone;
public Builder name(String name) {
this.name = name;
return this;
}
public Builder email(String email) {
this.email = email;
return this;
}
public Builder age(int age) {
this.age = age;
return this;
}
public User build() {
return new User(name, email, age, phone);
}
}
private User(String name, String email, int age, String phone) {
this.name = name;
this.email = email;
this.age = age;
this.phone = phone;
}
}
// Использование
User user = new User.Builder()
.name("John")
.email("john@example.com")
.age(30)
.build();
Prototype
Prototype позволяет создавать объекты через клонирование:
public class Document implements Cloneable {
private String title;
private List<String> pages;
@Override
public Document clone() throws CloneNotSupportedException {
Document cloned = (Document) super.clone();
cloned.pages = new ArrayList<>(this.pages); // Глубокое копирование
return cloned;
}
}
Document original = new Document("Report", pages);
Document copy = original.clone(); // Независимая копия
Структурные паттерны (Structural)
Adapter
Adapter позволяет интегрировать несовместимые интерфейсы:
// Старая система
public interface OldPaymentSystem {
void processPayment(String accountId, double amount);
}
// Новая система
public interface NewPaymentAPI {
void pay(String userId, BigDecimal sum);
}
// Адаптер
public class PaymentAdapter implements NewPaymentAPI {
private OldPaymentSystem oldSystem;
public PaymentAdapter(OldPaymentSystem oldSystem) {
this.oldSystem = oldSystem;
}
@Override
public void pay(String userId, BigDecimal sum) {
// Преобразуем новый интерфейс в старый
oldSystem.processPayment(userId, sum.doubleValue());
}
}
Decorator
Decorator добавляет функциональность объекту динамически:
public interface InputStream {
int read();
}
public class FileInputStream implements InputStream {
// Базовая реализация
}
public class BufferedInputStream implements InputStream {
private InputStream input;
public BufferedInputStream(InputStream input) {
this.input = input; // Оборачиваем
}
@Override
public int read() {
// Добавляем буферизацию
return input.read();
}
}
public class CompressedInputStream implements InputStream {
private InputStream input;
public CompressedInputStream(InputStream input) {
this.input = input;
}
@Override
public int read() {
// Добавляем декомпрессию
return input.read();
}
}
// Использование
InputStream stream = new CompressedInputStream(
new BufferedInputStream(
new FileInputStream()
)
); // Множественное обогащение функциональности
Facade
Facade упрощает работу со сложной подсистемой:
// Сложная подсистема с множеством классов
public class Database { }
public class Logger { }
public class Security { }
// Фасад
public class OrderService {
private Database db;
private Logger logger;
private Security security;
public void createOrder(Order order) {
security.validateUser();
logger.log("Creating order");
db.save(order);
logger.log("Order created");
}
}
// Клиент работает только с OrderService
OrderService service = new OrderService();
service.createOrder(order); // Простой интерфейс
Поведенческие паттерны (Behavioral)
Observer
Observer реализует подписку на изменения:
public interface EventListener {
void update(Event event);
}
public class EventManager {
private List<EventListener> listeners = new ArrayList<>();
public void subscribe(EventListener listener) {
listeners.add(listener);
}
public void notify(Event event) {
for (EventListener listener : listeners) {
listener.update(event);
}
}
}
public class UserRegisteredListener implements EventListener {
@Override
public void update(Event event) {
System.out.println("Sending welcome email...");
}
}
// Использование
EventManager manager = new EventManager();
manager.subscribe(new UserRegisteredListener());
manager.notify(new UserRegisteredEvent());
Strategy
Strategy инкапсулирует альтернативные алгоритмы:
public interface PaymentStrategy {
void pay(double amount);
}
public class CreditCardPayment implements PaymentStrategy {
@Override
public void pay(double amount) {
System.out.println("Paying " + amount + " by credit card");
}
}
public class PayPalPayment implements PaymentStrategy {
@Override
public void pay(double amount) {
System.out.println("Paying " + amount + " via PayPal");
}
}
public class Order {
private PaymentStrategy strategy;
public void setPaymentStrategy(PaymentStrategy strategy) {
this.strategy = strategy;
}
public void checkout(double amount) {
strategy.pay(amount); // Используем выбранную стратегию
}
}
Order order = new Order();
order.setPaymentStrategy(new CreditCardPayment());
order.checkout(100);
Command
Command инкапсулирует операцию как объект:
public interface Command {
void execute();
void undo();
}
public class OpenFileCommand implements Command {
private String filename;
public OpenFileCommand(String filename) {
this.filename = filename;
}
@Override
public void execute() {
System.out.println("Opening " + filename);
}
@Override
public void undo() {
System.out.println("Closing " + filename);
}
}
public class Editor {
private Stack<Command> history = new Stack<>();
public void executeCommand(Command command) {
command.execute();
history.push(command);
}
public void undo() {
if (!history.isEmpty()) {
history.pop().undo();
}
}
}
Когда использовать
- Builder — 3+ параметра конструктора
- Adapter — интеграция несовместимых систем
- Decorator — динамическое расширение функциональности
- Observer — реактивная архитектура, подписки
- Strategy — множество алгоритмов для одной задачи
- Facade — упрощение работы со сложными подсистемами
Заключение
Эффективное использование паттернов делает код модульным, расширяемым и тестируемым. Ключ в том, чтобы выбрать правильный паттерн для конкретной задачи, не переусложняя архитектуру.