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

Сталкивался ли с загроможденными методами

1.3 Junior🔥 251 комментариев
#SOLID и паттерны проектирования#Soft Skills и карьера

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

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

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

Загромождённые методы и рефакторинг

Да, абсолютно сталкивался. Загромождённые методы (bloated methods) — одна из самых распространённых проблем в legacy коде. Это методы, которые делают слишком много, содержат множество условий, вложенных циклов и логики разного уровня абстракции.

Примеры проблемы

Вот типичный загромождённый метод из реального проекта:

public void processOrder(Order order) {
    // Валидация
    if (order == null) throw new IllegalArgumentException("Order is null");
    if (order.getItems().isEmpty()) throw new IllegalArgumentException("Empty items");
    
    // Расчёт цены
    double total = 0;
    for (OrderItem item : order.getItems()) {
        if (item.getQuantity() <= 0) continue;
        double itemPrice = item.getPrice() * item.getQuantity();
        if (item.isDiscounted()) {
            itemPrice = itemPrice * 0.9;
        }
        total += itemPrice;
    }
    
    // Применение налога
    if (order.getCountry().equals("USA")) {
        total = total * 1.08;
    } else if (order.getCountry().equals("UK")) {
        total = total * 1.20;
    }
    
    // Отправка письма
    String recipient = order.getCustomer().getEmail();
    String subject = "Order #" + order.getId();
    String body = "Your order total: $" + total;
    emailService.send(recipient, subject, body);
    
    // Сохранение в БД
    order.setTotal(total);
    order.setStatus("PROCESSED");
    orderRepository.save(order);
    
    // Логирование
    logger.info("Processed order " + order.getId());
}

Этот метод делает 6 разных вещей. Это нарушает принцип Single Responsibility Principle (SRP).

Как я решаю такие проблемы

1. Извлечение методов (Extract Method)

Разбиваю логику на отдельные методы:

public void processOrder(Order order) {
    validateOrder(order);
    double total = calculateOrderTotal(order);
    applyTax(order, total);
    order.setTotal(total);
    order.setStatus("PROCESSED");
    
    orderRepository.save(order);
    sendConfirmationEmail(order, total);
    logOrderProcessing(order);
}

private void validateOrder(Order order) {
    if (order == null) throw new IllegalArgumentException("Order is null");
    if (order.getItems().isEmpty()) throw new IllegalArgumentException("Empty items");
}

private double calculateOrderTotal(Order order) {
    return order.getItems().stream()
        .filter(item -> item.getQuantity() > 0)
        .mapToDouble(item -> item.getPrice() * item.getQuantity())
        .map(price -> item.isDiscounted() ? price * 0.9 : price)
        .sum();
}

private void applyTax(Order order, double total) {
    double taxRate = getTaxRate(order.getCountry());
    total = total * (1 + taxRate);
}

private double getTaxRate(String country) {
    return switch(country) {
        case "USA" -> 0.08;
        case "UK" -> 0.20;
        default -> 0.0;
    };
}

private void sendConfirmationEmail(Order order, double total) {
    String recipient = order.getCustomer().getEmail();
    emailService.send(recipient, 
        "Order #" + order.getId(),
        "Your order total: $" + total);
}

private void logOrderProcessing(Order order) {
    logger.info("Processed order {}", order.getId());
}

2. Извлечение класса (Extract Class)

Логика может быть слишком сложной даже для методов. Тогда выделяю отдельные классы:

public class OrderProcessor {
    private final OrderValidator validator;
    private final OrderCalculator calculator;
    private final OrderRepository repository;
    private final EmailService emailService;
    
    public void processOrder(Order order) {
        validator.validate(order);
        OrderTotal total = calculator.calculate(order);
        order.setTotal(total.getAmount());
        order.setStatus("PROCESSED");
        
        repository.save(order);
        emailService.sendConfirmation(order, total);
    }
}

public class OrderValidator {
    public void validate(Order order) {
        if (order == null) throw new IllegalArgumentException("Order is null");
        if (order.getItems().isEmpty()) throw new IllegalArgumentException("Empty items");
    }
}

public class OrderCalculator {
    public OrderTotal calculate(Order order) {
        double subtotal = calculateSubtotal(order);
        double tax = calculateTax(order, subtotal);
        return new OrderTotal(subtotal, tax);
    }
    
    private double calculateSubtotal(Order order) {
        return order.getItems().stream()
            .filter(item -> item.getQuantity() > 0)
            .mapToDouble(this::calculateItemPrice)
            .sum();
    }
    
    private double calculateItemPrice(OrderItem item) {
        double price = item.getPrice() * item.getQuantity();
        return item.isDiscounted() ? price * 0.9 : price;
    }
    
    private double calculateTax(Order order, double subtotal) {
        double rate = getTaxRate(order.getCountry());
        return subtotal * rate;
    }
}

3. Удаление условной логики (Replace Conditional with Polymorphism)

// Вместо if/else
public interface TaxCalculator {
    double calculateTax(double amount);
}

public class USATaxCalculator implements TaxCalculator {
    @Override
    public double calculateTax(double amount) {
        return amount * 0.08;
    }
}

public class UKTaxCalculator implements TaxCalculator {
    @Override
    public double calculateTax(double amount) {
        return amount * 0.20;
    }
}

public class TaxCalculatorFactory {
    public TaxCalculator getTaxCalculator(String country) {
        return switch(country) {
            case "USA" -> new USATaxCalculator();
            case "UK" -> new UKTaxCalculator();
            default -> amount -> 0;
        };
    }
}

4. Использование Stream API и функциональной парадигмы

Вместо imperативных циклов — declarative подход:

// Плохо
List<Integer> prices = new ArrayList<>();
for (OrderItem item : order.getItems()) {
    if (item.getQuantity() > 0) {
        prices.add(item.getPrice());
    }
}

// Хорошо
List<Integer> prices = order.getItems().stream()
    .filter(item -> item.getQuantity() > 0)
    .map(OrderItem::getPrice)
    .toList();

Признаки загромождённого метода

  • Больше 20 строк кода — красный флаг
  • Больше 3 параметров — сложновато тестировать
  • Больше 3 уровней вложенности — трудно понять
  • Несколько ответственностей — нарушает SRP
  • Сложно назвать одним глаголом — значит, делает много
  • Трудно тестировать — признак плохого дизайна

Мой подход при code review

  1. Спрашиваю: "Что этот метод делает?"
  2. Если ответ содержит несколько "и", "также", "затем" — нужен рефакторинг
  3. Предлагаю простые улучшения: Extract Method
  4. Потом более сложные: Extract Class, Polymorphism
  5. Всегда пишу тесты после рефакторинга

Инструменты

IDE помогают:

  • IntelliJ IDEA: Refactor → Extract Method/Class
  • SonarQube: находит методы с high complexity
  • Metrics плагины: показывают Cyclomatic Complexity

Вывод

Загромождённые методы — это техдолг. Лучше потратить время на рефакторинг сразу, чем потом месяцы искать баги в 300-строчном методе. Clean code — это не эстетика, это инвестиция в поддерживаемость и скорость разработки.