← Назад к вопросам
Что такое антипаттерн?
2.0 Middle🔥 151 комментариев
#SOLID и паттерны проектирования
Комментарии (1)
🐱
claude-haiku-4.5PrepBro AI23 мар. 2026 г.(ред.)
Ответ сгенерирован нейросетью и может содержать ошибки
Антипаттерн
Антипаттерн (anti-pattern) — это повторяющееся решение проблемы, которое выглядит хорошим на первый взгляд, но приводит к неправильным последствиям. Это противоположность паттерну проектирования — вместо того, чтобы решать проблему, антипаттерн её усугубляет.
Ключевые характеристики антипаттерна
- Кажется логичным и простым первоначально
- Приводит к техническому долгу и сложностям
- Повторяется во многих кодовых базах
- Снижает качество, производительность или поддерживаемость кода
- Со временем стоит всё дороже в поддержке
Классические антипаттерны в Java
1. God Object (Божественный объект)
Один класс отвечает за слишком много функциональности:
// ❌ ПЛОХО: God Object
public class UserManager {
// Управление пользователями
public void createUser(User user) { }
public void deleteUser(Long id) { }
// Управление базой данных
public void saveToDatabase(User user) { }
public User getFromDatabase(Long id) { }
// Валидация
public boolean validateUser(User user) { }
// Email отправка
public void sendWelcomeEmail(User user) { }
// Логирование
public void logUserActivity(User user) { }
// Аудит
public void auditUserChanges(User user) { }
}
// ✅ ХОРОШО: Разделение ответственности
public class UserService {
private UserRepository repository;
private EmailService emailService;
public void createUser(User user) {
repository.save(user);
emailService.sendWelcomeEmail(user);
}
}
public class UserRepository {
public void save(User user) { }
}
public class EmailService {
public void sendWelcomeEmail(User user) { }
}
2. Circular Dependency (Циклическая зависимость)
Когда классы зависят друг от друга, создавая цикл:
// ❌ ПЛОХО: Циклическая зависимость
public class UserService {
private OrderService orderService;
public void createUser(User user) {
orderService.createDefaultOrder(user);
}
}
public class OrderService {
private UserService userService;
public void createDefaultOrder(User user) {
// Вызывает userService где-то, создавая цикл
}
}
// ✅ ХОРОШО: Использование events или промежуточного сервиса
public class ApplicationService {
private UserService userService;
private OrderService orderService;
public void registerNewUser(User user) {
userService.createUser(user);
orderService.createDefaultOrder(user);
}
}
3. Null Pointer Exception Hell (Ад указателей на null)
Постоянная проверка на null, усложняющая код:
// ❌ ПЛОХО: Множество проверок на null
public String getUserCity(User user) {
if (user != null) {
Address address = user.getAddress();
if (address != null) {
City city = address.getCity();
if (city != null) {
return city.getName();
}
}
}
return "Unknown";
}
// ✅ ХОРОШО: Optional в Java 8+
public String getUserCity(User user) {
return Optional.ofNullable(user)
.map(User::getAddress)
.map(Address::getCity)
.map(City::getName)
.orElse("Unknown");
}
4. Magic Numbers & Magic Strings (Магические числа и строки)
Хардкоженные значения без объяснения:
// ❌ ПЛОХО: Магические числа
public class PaymentProcessor {
public void processPayment(double amount) {
if (amount < 0 || amount > 99999) { // Откуда эти числа?
throw new IllegalArgumentException();
}
double fee = amount * 0.015; // Почему 0.015?
if (amount > 1000) { // Почему 1000?
applyDiscount();
}
}
}
// ✅ ХОРОШО: Константы с понятными именами
public class PaymentProcessor {
private static final double MIN_PAYMENT = 0;
private static final double MAX_PAYMENT = 99999;
private static final double STANDARD_FEE_RATE = 0.015;
private static final double DISCOUNT_THRESHOLD = 1000;
public void processPayment(double amount) {
if (amount < MIN_PAYMENT || amount > MAX_PAYMENT) {
throw new IllegalArgumentException("Invalid amount");
}
double fee = amount * STANDARD_FEE_RATE;
if (amount > DISCOUNT_THRESHOLD) {
applyDiscount();
}
}
}
5. Spaghetti Code (Спагетти код)
Код с запутанным потоком управления:
// ❌ ПЛОХО: Спагетти логика
public void processOrder(Order order) {
if (order.getItems().size() > 0) {
double total = 0;
for (Item item : order.getItems()) {
total += item.getPrice();
if (item.isAvailable()) {
if (order.getUser().isPremium()) {
total *= 0.9;
if (item.getCategory().equals("ELECTRONICS")) {
total *= 0.95;
}
}
}
}
}
}
// ✅ ХОРОШО: Чистый, понятный код
public void processOrder(Order order) {
PriceCalculator calculator = new PriceCalculator(order.getUser());
double total = order.getItems().stream()
.filter(Item::isAvailable)
.mapToDouble(item -> calculator.calculatePrice(item))
.sum();
order.setTotal(total);
}
6. Copy-Paste Programming (Копипаст программирование)
Дублирование кода вместо рефакторинга:
// ❌ ПЛОХО: Дублирование
public class UserValidator {
public boolean validateEmail(String email) {
if (email == null || email.isEmpty()) return false;
if (!email.contains("@")) return false;
if (!email.contains(".")) return false;
return true;
}
}
public class ProductValidator {
public boolean validateContactEmail(String email) {
if (email == null || email.isEmpty()) return false;
if (!email.contains("@")) return false;
if (!email.contains(".")) return false;
return true;
}
}
// ✅ ХОРОШО: Общий валидатор
public class EmailValidator {
public boolean validate(String email) {
if (email == null || email.isEmpty()) return false;
if (!email.contains("@")) return false;
if (!email.contains(".")) return false;
return true;
}
}
public class UserValidator {
private EmailValidator emailValidator;
public boolean validateEmail(String email) {
return emailValidator.validate(email);
}
}
7. Premature Optimization (Преждевременная оптимизация)
Оптимизация без доказательства, что это необходимо:
// ❌ ПЛОХО: Оверкомплексная оптимизация
public List<User> getActiveUsers() {
// Сложная система кэширования, несколько слоёв оптимизации
// Но профилер показывает, что это узкое место в 0.1% случаев
return complexCacheLogic();
}
// ✅ ХОРОШО: Сначала просто и понятно
public List<User> getActiveUsers() {
return users.stream()
.filter(User::isActive)
.collect(Collectors.toList());
}
// Если профилер покажет проблемы — тогда оптимизировать
8. Over-Engineering (Переинжиниринг)
Добавление сложности "на будущее":
// ❌ ПЛОХО: Переинжиниринг
public abstract class BaseEntity {
// 20 методов утилит
// 15 конфигов
// 3 слоя абстракций
// "может пригодиться в будущем"
}
// ✅ ХОРОШО: YAGNI (You Aren't Gonna Need It)
public class User {
private Long id;
private String name;
// Только то, что реально нужно сейчас
}
Почему антипаттерны вредны
- Снижают производительность — неправильная архитектура
- Усложняют тестирование — тесты становятся хрупкими
- Увеличивают время разработки — нужно больше работать с плохим кодом
- Повышают стоимость поддержки — технический долг растёт
- Усложняют сотрудничество — новые разработчики не понимают код
Как избежать антипаттернов
- Изучайте паттерны проектирования (Design Patterns)
- Следуйте SOLID принципам
- Пишите чистый код (Clean Code)
- Code Review с опытными разработчиками
- Рефакторинг — постоянно улучшайте код
- Тестирование — покрывайте код тестами
- Инструменты анализа (SonarQube, Checkstyle)
Антипаттерны — это учебные материалы, показывающие, как не нужно писать код.