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

На что обратишь внимание при Refactoring класса?

2.3 Middle🔥 191 комментариев
#SOLID и паттерны проектирования

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

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

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

На что обратить внимание при рефакторинге класса

Рефакторинг - это улучшение кода без изменения функциональности. Вот систематический подход.

1. SOLID принципы

Single Responsibility Principle (SRP)

// ❌ ПЛОХО - класс делает несколько вещей
public class UserManager {
    
    public User createUser(String name, String email) {
        // Создание пользователя
        User user = new User(name, email);
        
        // Отправка email (не касается управления пользователями!)
        sendWelcomeEmail(email);
        
        // Логирование (слишком низкоуровневое)
        logToFile("User created: " + name);
        
        // Сохранение в БД (работа с БД)
        saveToDatabase(user);
        
        return user;
    }
}

// ✅ ХОРОШО - каждый класс отвечает за одно
@Service
public class UserService {
    private final UserRepository repository;
    private final EmailService emailService;
    
    public User createUser(String name, String email) {
        User user = new User(name, email);
        repository.save(user);
        emailService.sendWelcomeEmail(email);
        return user;
    }
}

@Service
public class EmailService {
    public void sendWelcomeEmail(String email) {
        // отправка email
    }
}

@Repository
public class UserRepository {
    public void save(User user) {
        // сохранение в БД
    }
}

Open/Closed Principle (OCP)

// ❌ ПЛОХО - нужно менять класс для добавления новых типов
public class ReportGenerator {
    
    public void generateReport(String type) {
        if (type.equals("PDF")) {
            // код для PDF
        } else if (type.equals("EXCEL")) {
            // код для Excel
        } else if (type.equals("CSV")) {
            // код для CSV
        }
    }
}

// ✅ ХОРОШО - открыт для расширения, закрыт для модификации
public interface ReportFormat {
    void generate(Data data);
}

public class PDFReportFormat implements ReportFormat {
    @Override
    public void generate(Data data) {
        // PDF логика
    }
}

public class ExcelReportFormat implements ReportFormat {
    @Override
    public void generate(Data data) {
        // Excel логика
    }
}

public class ReportGenerator {
    private final ReportFormat format;
    
    public void generate(Data data) {
        format.generate(data);
    }
}

2. DRY (Don't Repeat Yourself)

// ❌ ПЛОХО - код повторяется
public class DataValidator {
    
    public boolean validateEmail(String email) {
        if (email == null || email.isEmpty() || 
            !email.contains("@") || email.length() < 5) {
            return false;
        }
        return true;
    }
    
    public boolean validatePhone(String phone) {
        if (phone == null || phone.isEmpty() || 
            !phone.matches("\\d{10}") || phone.length() < 10) {
            return false;
        }
        return true;
    }
    
    public boolean validateName(String name) {
        if (name == null || name.isEmpty() || name.length() < 2) {
            return false;
        }
        return true;
    }
}

// ✅ ХОРОШО - извлекли общую логику
public class DataValidator {
    
    private boolean isValidString(String value, String regex, int minLength) {
        return value != null && !value.isEmpty() && 
               value.length() >= minLength && value.matches(regex);
    }
    
    public boolean validateEmail(String email) {
        return isValidString(email, ".*@.*", 5);
    }
    
    public boolean validatePhone(String phone) {
        return isValidString(phone, "\\d{10}", 10);
    }
    
    public boolean validateName(String name) {
        return isValidString(name, ".*", 2);
    }
}

3. KISS (Keep It Simple, Stupid)

// ❌ ПЛОХО - переусложнено
public class DateCalculator {
    
    public LocalDate calculateDeadline(LocalDate startDate, int daysCount) {
        // Странная логика с временными поясами и прочим
        ZonedDateTime zoned = startDate.atStartOfDay(ZoneId.of("UTC"));
        long milliseconds = daysCount * 24L * 60L * 60L * 1000L;
        Instant instant = Instant.ofEpochMilli(zoned.toInstant().toEpochMilli() + milliseconds);
        return LocalDateTime.ofInstant(instant, ZoneId.of("UTC")).toLocalDate();
    }
}

// ✅ ХОРОШО - простое решение
public class DateCalculator {
    
    public LocalDate calculateDeadline(LocalDate startDate, int daysCount) {
        return startDate.plusDays(daysCount);
    }
}

4. YAGNI (You Aren't Gonna Need It)

// ❌ ПЛОХО - добавляем функции "на будущее"
public class UserService {
    
    // Никто не использует эти методы
    public List<User> findUsersByComplexCriteria(...) { }
    public void synchronizeWithExternalSystem() { }
    public Map<String, Object> getDetailedAnalytics() { }
    
    // А эти используются
    public User findById(Long id) { }
    public void save(User user) { }
}

// ✅ ХОРОШО - только нужный функционал
public class UserService {
    
    public User findById(Long id) { }
    public void save(User user) { }
}

5. Качество кода

Имена переменных

// ❌ ПЛОХО
public class UserManager {
    public List<User> u;
    public Map<Integer, String> mp;
    
    public void proc(int x) { }
}

// ✅ ХОРОШО
public class UserManager {
    private List<User> users;
    private Map<Integer, String> userIdToNameMapping;
    
    public void processUser(int userId) { }
}

Размер методов

// ❌ ПЛОХО - метод делает слишком много
public void processOrder(Order order) {
    // 100 строк кода
    // валидация
    // расчеты
    // отправка email
    // логирование
    // обновление БД
}

// ✅ ХОРОШО - методы маленькие и понятные
public void processOrder(Order order) {
    validateOrder(order);
    calculatePrice(order);
    saveToDatabase(order);
    notifyCustomer(order);
}

private void validateOrder(Order order) { }
private void calculatePrice(Order order) { }
private void saveToDatabase(Order order) { }
private void notifyCustomer(Order order) { }

Количество параметров

// ❌ ПЛОХО - слишком много параметров
public void createReport(String title, String author, LocalDate date, 
                         String format, int width, int height, 
                         boolean includeChart, String chartType,
                         boolean includeTable, String[] columns) { }

// ✅ ХОРОШО - используем объект
public void createReport(ReportConfig config) { }

public class ReportConfig {
    private String title;
    private String author;
    private LocalDate date;
    private String format;
    private int width;
    private int height;
    private boolean includeChart;
    private String chartType;
    // ... и т.д.
}

6. Правильная архитектура слоев

// ❌ ПЛОХО - смешаны слои
@RestController
public class UserController {
    
    @GetMapping("/users/{id}")
    public UserDTO getUser(Long id) {
        // Прямо в контроллере делаем запрос в БД!
        User user = new User();
        PreparedStatement stmt = getConnection().prepareStatement("SELECT * FROM users WHERE id = ?");
        stmt.setLong(1, id);
        ResultSet rs = stmt.executeQuery();
        // ... кучу кода ...
        return mapToDTO(user);
    }
}

// ✅ ХОРОШО - разделены слои
@RestController
@RequestMapping("/users")
public class UserController {
    
    private final UserService userService;
    
    @GetMapping("/{id}")
    public UserDTO getUser(@PathVariable Long id) {
        User user = userService.findById(id);
        return mapper.toDTO(user);
    }
}

@Service
public class UserService {
    
    private final UserRepository repository;
    
    public User findById(Long id) {
        return repository.findById(id)
            .orElseThrow(() -> new NotFoundException("User not found"));
    }
}

@Repository
public class UserRepository extends JpaRepository<User, Long> { }

7. Тестируемость

// ❌ ПЛОХО - сложно тестировать
public class OrderService {
    
    public void processOrder(Order order) {
        // Hardcoded зависимости
        EmailService emailService = new EmailService();
        Database db = new Database();
        
        db.save(order);
        emailService.send("order@email.com", "New order");
    }
}

// ✅ ХОРОШО - легко мокировать
@Service
public class OrderService {
    
    private final OrderRepository repository;
    private final EmailService emailService;
    
    public OrderService(OrderRepository repository, EmailService emailService) {
        this.repository = repository;
        this.emailService = emailService;
    }
    
    public void processOrder(Order order) {
        repository.save(order);
        emailService.send("order@email.com", "New order");
    }
}

// Тестирование
@Test
public void testProcessOrder() {
    OrderRepository mockRepo = mock(OrderRepository.class);
    EmailService mockEmail = mock(EmailService.class);
    OrderService service = new OrderService(mockRepo, mockEmail);
    
    service.processOrder(new Order());
    
    verify(mockRepo).save(any(Order.class));
    verify(mockEmail).send(anyString(), anyString());
}

8. Контрольный список рефакторинга

  • Соответствует SOLID принципам?
  • Нет дублирования кода (DRY)?
  • Простота и понятность (KISS)?
  • Нет лишнего функционала (YAGNI)?
  • Хорошие имена переменных и методов?
  • Методы маленькие (< 20 строк)?
  • Количество параметров < 3?
  • Разделены слои (Presentation → Application → Domain)?
  • Класс тестируем?
  • Нет hardcoded зависимостей?
  • Обработка ошибок правильная?
  • Нет magic strings/numbers?
  • Comments актуальны или не нужны?
  • Все тесты проходят?

Порядок рефакторинга

  1. Проверь тесты - они должны быть зелёные перед рефакторингом
  2. Рефакторь маленькими шагами - каждый шаг должен быть проверяем
  3. Запускай тесты после каждого изменения
  4. Используй IDE - Rename, Extract Method, Move Class
  5. Код Review - попроси коллеги проверить рефакторинг

Итоговый ответ на интервью

"При рефакторинге я обращаю внимание на:

  1. SOLID принципы - каждый класс должен отвечать за одно
  2. DRY - нет дублирования кода
  3. KISS - решение должно быть простым
  4. Чистота кода - хорошие имена, маленькие методы
  5. Архитектура - разделение слоев (Presentation → Application → Domain)
  6. Тестируемость - внедрение зависимостей, mocking
  7. Документация - актуальные комментарии

Я делаю рефакторинг итеративно, запуская тесты после каждого изменения, используя инструменты IDE для безопасности."