← Назад к вопросам

С какими шаблонами проектирования работал

1.2 Junior🔥 181 комментариев
#ORM и Hibernate#Spring Boot и Spring Data#Базы данных и SQL

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI23 мар. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Шаблоны проектирования (Design Patterns) в моей практике

В своей разработке применял множество шаблонов из классификации Gang of Four и архитектурные паттерны. Опишу наиболее часто используемые с практическими примерами.

Creational Patterns (Порождающие)

1. Singleton

// Используется для единственного экземпляра ресурса
public class DatabaseConnectionPool {
    private static DatabaseConnectionPool instance;
    private final DataSource dataSource;

    private DatabaseConnectionPool() {
        this.dataSource = createDataSource();
    }

    public static synchronized DatabaseConnectionPool getInstance() {
        if (instance == null) {
            instance = new DatabaseConnectionPool();
        }
        return instance;
    }

    public Connection getConnection() throws SQLException {
        return dataSource.getConnection();
    }
}

// Более безопасный вариант
public class DatabaseConnectionPool {
    private static final DatabaseConnectionPool INSTANCE = 
        new DatabaseConnectionPool();
    
    private DatabaseConnectionPool() {}
    
    public static DatabaseConnectionPool getInstance() {
        return INSTANCE;
    }
}

2. Factory Pattern

// Создание семейства объектов без привязки к конкретным классам
public interface PaymentProcessor {
    void process(Payment payment);
}

public class CreditCardProcessor implements PaymentProcessor {
    @Override
    public void process(Payment payment) {
        System.out.println("Processing credit card payment");
    }
}

public class PayPalProcessor implements PaymentProcessor {
    @Override
    public void process(Payment payment) {
        System.out.println("Processing PayPal payment");
    }
}

public class PaymentProcessorFactory {
    public static PaymentProcessor createProcessor(PaymentMethod method) {
        return switch(method) {
            case CREDIT_CARD -> new CreditCardProcessor();
            case PAYPAL -> new PayPalProcessor();
            case BANK_TRANSFER -> new BankTransferProcessor();
            default -> throw new IllegalArgumentException("Unknown method");
        };
    }
}

// Использование
public class OrderService {
    public void checkout(Order order) {
        PaymentProcessor processor = 
            PaymentProcessorFactory.createProcessor(order.getPaymentMethod());
        processor.process(order.getPayment());
    }
}

3. Builder Pattern

// Для построения сложных объектов с множеством параметров
public class UserDto {
    private final String email;
    private final String firstName;
    private final String lastName;
    private final int age;
    private final String phone;
    private final String address;

    private UserDto(Builder builder) {
        this.email = builder.email;
        this.firstName = builder.firstName;
        this.lastName = builder.lastName;
        this.age = builder.age;
        this.phone = builder.phone;
        this.address = builder.address;
    }

    public static class Builder {
        private final String email;
        private String firstName;
        private String lastName;
        private int age;
        private String phone;
        private String address;

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

        public Builder firstName(String firstName) {
            this.firstName = firstName;
            return this;
        }

        public Builder lastName(String lastName) {
            this.lastName = lastName;
            return this;
        }

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

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

// Использование
UserDto user = new UserDto.Builder("john@example.com")
    .firstName("John")
    .lastName("Doe")
    .age(30)
    .phone("+1234567890")
    .build();

Structural Patterns (Структурные)

1. Proxy Pattern

// Контролированный доступ к объекту
public interface UserService {
    User getUser(Long id);
    void updateUser(User user);
}

public class UserServiceImpl implements UserService {
    @Override
    public User getUser(Long id) {
        return userRepository.findById(id).orElse(null);
    }
    
    @Override
    public void updateUser(User user) {
        userRepository.save(user);
    }
}

public class UserServiceProxy implements UserService {
    private final UserService userService;
    private final SecurityContext securityContext;

    public UserServiceProxy(UserService userService, 
                           SecurityContext securityContext) {
        this.userService = userService;
        this.securityContext = securityContext;
    }

    @Override
    public User getUser(Long id) {
        if (!securityContext.hasPermission("read_user")) {
            throw new AccessDeniedException("Access denied");
        }
        return userService.getUser(id);
    }

    @Override
    public void updateUser(User user) {
        if (!securityContext.hasPermission("write_user")) {
            throw new AccessDeniedException("Access denied");
        }
        userService.updateUser(user);
    }
}

2. Decorator Pattern

// Динамическое расширение функциональности объектов
public interface Coffee {
    double cost();
    String description();
}

public class SimpleCoffee implements Coffee {
    @Override
    public double cost() {
        return 2.0;
    }
    
    @Override
    public String description() {
        return "Simple coffee";
    }
}

public abstract class CoffeeDecorator implements Coffee {
    protected Coffee coffee;
    
    public CoffeeDecorator(Coffee coffee) {
        this.coffee = coffee;
    }
}

public class MilkDecorator extends CoffeeDecorator {
    public MilkDecorator(Coffee coffee) {
        super(coffee);
    }
    
    @Override
    public double cost() {
        return coffee.cost() + 0.5;
    }
    
    @Override
    public String description() {
        return coffee.description() + ", milk";
    }
}

public class SugarDecorator extends CoffeeDecorator {
    public SugarDecorator(Coffee coffee) {
        super(coffee);
    }
    
    @Override
    public double cost() {
        return coffee.cost() + 0.2;
    }
    
    @Override
    public String description() {
        return coffee.description() + ", sugar";
    }
}

// Использование
Coffee coffee = new SimpleCoffee();
coffee = new MilkDecorator(coffee);
coffee = new SugarDecorator(coffee);
System.out.println(coffee.description()); // Simple coffee, milk, sugar
System.out.println(coffee.cost()); // 2.7

3. Adapter Pattern

// Преобразование несовместимых интерфейсов
public interface PaymentGateway {
    boolean pay(String accountNumber, BigDecimal amount);
}

public class LegacyPaymentSystem {
    public boolean processPayment(String account, double amount) {
        System.out.println("Legacy system processing: " + amount);
        return true;
    }
}

public class PaymentGatewayAdapter implements PaymentGateway {
    private final LegacyPaymentSystem legacySystem;
    
    public PaymentGatewayAdapter(LegacyPaymentSystem legacySystem) {
        this.legacySystem = legacySystem;
    }
    
    @Override
    public boolean pay(String accountNumber, BigDecimal amount) {
        return legacySystem.processPayment(accountNumber, amount.doubleValue());
    }
}

Behavioral Patterns (Поведенческие)

1. Strategy Pattern

// Выбор алгоритма в runtime
public interface SortingStrategy {
    void sort(int[] array);
}

public class QuickSort implements SortingStrategy {
    @Override
    public void sort(int[] array) {
        // QuickSort реализация
    }
}

public class MergeSort implements SortingStrategy {
    @Override
    public void sort(int[] array) {
        // MergeSort реализация
    }
}

public class DataSorter {
    private SortingStrategy strategy;
    
    public void setStrategy(SortingStrategy strategy) {
        this.strategy = strategy;
    }
    
    public void sort(int[] array) {
        strategy.sort(array);
    }
}

// Использование
DataSorter sorter = new DataSorter();
sorter.setStrategy(new QuickSort());
sorter.sort(array);

sorter.setStrategy(new MergeSort());
sorter.sort(array);

2. Observer Pattern

// Event-driven архитектура
public interface OrderObserver {
    void update(Order order);
}

public class EmailNotifier implements OrderObserver {
    @Override
    public void update(Order order) {
        System.out.println("Sending email for order: " + order.getId());
    }
}

public class SMSNotifier implements OrderObserver {
    @Override
    public void update(Order order) {
        System.out.println("Sending SMS for order: " + order.getId());
    }
}

public class OrderManager {
    private final List<OrderObserver> observers = new ArrayList<>();
    
    public void registerObserver(OrderObserver observer) {
        observers.add(observer);
    }
    
    public void removeObserver(OrderObserver observer) {
        observers.remove(observer);
    }
    
    public void notifyObservers(Order order) {
        for (OrderObserver observer : observers) {
            observer.update(order);
        }
    }
    
    public void placeOrder(Order order) {
        // Логика обработки заказа
        notifyObservers(order);
    }
}

3. Command Pattern

// Инкапсуляция запроса как объекта
public interface Command {
    void execute();
    void undo();
}

public class TransferMoneyCommand implements Command {
    private final Account from;
    private final Account to;
    private final BigDecimal amount;
    
    public TransferMoneyCommand(Account from, Account to, BigDecimal amount) {
        this.from = from;
        this.to = to;
        this.amount = amount;
    }
    
    @Override
    public void execute() {
        from.withdraw(amount);
        to.deposit(amount);
    }
    
    @Override
    public void undo() {
        from.deposit(amount);
        to.withdraw(amount);
    }
}

public class TransactionManager {
    private final List<Command> commandHistory = new ArrayList<>();
    
    public void execute(Command command) {
        command.execute();
        commandHistory.add(command);
    }
    
    public void undoLastCommand() {
        if (!commandHistory.isEmpty()) {
            Command lastCommand = commandHistory.remove(commandHistory.size() - 1);
            lastCommand.undo();
        }
    }
}

4. State Pattern

// Изменение поведения объекта при смене состояния
public interface OrderState {
    void processOrder(Order order);
    void cancelOrder(Order order);
}

public class PendingState implements OrderState {
    @Override
    public void processOrder(Order order) {
        System.out.println("Processing order...");
        order.setState(new ProcessingState());
    }
    
    @Override
    public void cancelOrder(Order order) {
        System.out.println("Order cancelled");
        order.setState(new CancelledState());
    }
}

public class ProcessingState implements OrderState {
    @Override
    public void processOrder(Order order) {
        System.out.println("Shipping order...");
        order.setState(new ShippedState());
    }
    
    @Override
    public void cancelOrder(Order order) {
        System.out.println("Cannot cancel while processing");
    }
}

public class Order {
    private OrderState state = new PendingState();
    
    public void processOrder() {
        state.processOrder(this);
    }
    
    public void setState(OrderState state) {
        this.state = state;
    }
}

Архитектурные паттерны

1. MVC (Model-View-Controller)

Использую в Spring MVC приложениях.

2. Repository Pattern

public interface UserRepository {
    User findById(Long id);
    void save(User user);
    void delete(Long id);
}

public class UserRepositoryImpl implements UserRepository {
    private final DataSource dataSource;
    
    @Override
    public User findById(Long id) {
        // Database query
    }
    
    @Override
    public void save(User user) {
        // Database insert/update
    }
}

3. Dependency Injection

public class UserService {
    private final UserRepository repository;
    private final EmailService emailService;
    
    // Constructor injection
    public UserService(UserRepository repository, EmailService emailService) {
        this.repository = repository;
        this.emailService = emailService;
    }
}

4. Aspect-Oriented Programming (AOP)

@Aspect
@Component
public class LoggingAspect {
    @Around("execution(* com.example.service.*.*(..))")  
    public Object logMethodExecution(ProceedingJoinPoint joinPoint) 
        throws Throwable {
        long startTime = System.currentTimeMillis();
        
        try {
            return joinPoint.proceed();
        } finally {
            long duration = System.currentTimeMillis() - startTime;
            System.out.println("Method " + joinPoint.getSignature() + 
                " took " + duration + "ms");
        }
    }
}

Итого

Часто используемые:

  • Factory (для создания объектов)
  • Strategy (для выбора алгоритма)
  • Observer (для event-driven систем)
  • Decorator (для расширения функциональности)
  • Builder (для сложных объектов)

Менее часто, но когда нужны:

  • Command (для undo/redo)
  • State (для конечных автоматов)
  • Proxy (для контроля доступа)
  • Adapter (для интеграции legacy систем)

Знание паттернов позволяет писать более гибкий, поддерживаемый и расширяемый код.

С какими шаблонами проектирования работал | PrepBro