← Назад к вопросам
На что обратишь внимание при 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 актуальны или не нужны?
- Все тесты проходят?
Порядок рефакторинга
- Проверь тесты - они должны быть зелёные перед рефакторингом
- Рефакторь маленькими шагами - каждый шаг должен быть проверяем
- Запускай тесты после каждого изменения
- Используй IDE - Rename, Extract Method, Move Class
- Код Review - попроси коллеги проверить рефакторинг
Итоговый ответ на интервью
"При рефакторинге я обращаю внимание на:
- SOLID принципы - каждый класс должен отвечать за одно
- DRY - нет дублирования кода
- KISS - решение должно быть простым
- Чистота кода - хорошие имена, маленькие методы
- Архитектура - разделение слоев (Presentation → Application → Domain)
- Тестируемость - внедрение зависимостей, mocking
- Документация - актуальные комментарии
Я делаю рефакторинг итеративно, запуская тесты после каждого изменения, используя инструменты IDE для безопасности."