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

Какой знаешь самый распространенный паттерн?

1.2 Junior🔥 141 комментариев
#SOLID и паттерны проектирования

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

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

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

Какой знаешь самый распространенный паттерн

В Java существуют десятки паттернов проектирования, но несколько из них встречаются буквально в каждом проекте. Я расскажу о самых распространённых и их практическом применении.

1. Singleton (Одиночка)

Это, вероятно, самый используемый паттерн в Java. Гарантирует, что класс имеет только один экземпляр в приложении.

Где встречается:

  • Database connections pool
  • Logger instances
  • Configuration readers
  • Thread pools
// Базовая реализация (потокобезопасная)
public class DatabaseConnectionPool {
    private static volatile DatabaseConnectionPool instance;
    
    private DatabaseConnectionPool() {
        // Приватный конструктор
    }
    
    public static DatabaseConnectionPool getInstance() {
        if (instance == null) {
            synchronized (DatabaseConnectionPool.class) {
                if (instance == null) {
                    instance = new DatabaseConnectionPool();
                }
            }
        }
        return instance;
    }
}

// Использование
DatabaseConnectionPool pool = DatabaseConnectionPool.getInstance();
Connection conn = pool.getConnection();

Лучший способ (Enum):

public enum DatabaseConnectionPool {
    INSTANCE;
    
    private HikariCP hikari;
    
    DatabaseConnectionPool() {
        this.hikari = new HikariCP();
    }
    
    public Connection getConnection() {
        return hikari.getConnection();
    }
}

// Использование
Connection conn = DatabaseConnectionPool.INSTANCE.getConnection();

2. Dependency Injection (DI)

В Spring это встроено, но это по-прежнему паттерн, и он критичен для качественного кода.

Проблема без DI:

public class UserService {
    private DatabaseConnection db = new DatabaseConnection(); // tight coupling!
    
    public User findUser(Long id) {
        return db.query("SELECT * FROM users WHERE id = ?", id);
    }
}

// Сложно тестировать!

С Dependency Injection:

public class UserService {
    private final DatabaseConnection db;
    
    // Конструктор инъекции
    public UserService(DatabaseConnection db) {
        this.db = db; // loose coupling!
    }
    
    public User findUser(Long id) {
        return db.query("SELECT * FROM users WHERE id = ?", id);
    }
}

// В Spring
@Service
public class UserService {
    private final UserRepository userRepository;
    
    // Spring автоматически инъектирует
    public UserService(UserRepository userRepository) {
        this.userRepository = userRepository;
    }
}

Преимущества:

  • Тестируется через mock'и
  • Слабая связанность
  • Гибкость и переиспользование

3. Factory (Фабрика)

Отделяет создание объектов от их использования. Очень частый паттерн.

Простой пример:

public class PaymentMethodFactory {
    
    public static PaymentProcessor createProcessor(PaymentType type) {
        switch (type) {
            case CREDIT_CARD:
                return new CreditCardProcessor();
            case PAYPAL:
                return new PayPalProcessor();
            case CRYPTOCURRENCY:
                return new CryptoProcessor();
            default:
                throw new IllegalArgumentException("Unknown payment type");
        }
    }
}

// Использование
PaymentProcessor processor = PaymentMethodFactory.createProcessor(PaymentType.PAYPAL);
processor.process(100.0);

В Spring (более красиво):

@Component
public class PaymentProcessorFactory {
    private final Map<PaymentType, PaymentProcessor> processors;
    
    public PaymentProcessorFactory(
        CreditCardProcessor creditCardProcessor,
        PayPalProcessor payPalProcessor,
        CryptoProcessor cryptoProcessor
    ) {
        this.processors = Map.of(
            PaymentType.CREDIT_CARD, creditCardProcessor,
            PaymentType.PAYPAL, payPalProcessor,
            PaymentType.CRYPTOCURRENCY, cryptoProcessor
        );
    }
    
    public PaymentProcessor getProcessor(PaymentType type) {
        return processors.getOrDefault(type, () -> {
            throw new IllegalArgumentException("Unknown payment type");
        });
    }
}

4. Builder (Строитель)

Строит сложные объекты пошагово. Очень удобен для объектов с множеством параметров.

public class HttpRequest {
    private final String url;
    private final String method;
    private final Map<String, String> headers;
    private final String body;
    private final int timeout;
    
    // Приватный конструктор
    private HttpRequest(HttpRequest.Builder builder) {
        this.url = builder.url;
        this.method = builder.method;
        this.headers = builder.headers;
        this.body = builder.body;
        this.timeout = builder.timeout;
    }
    
    // Builder класс
    public static class Builder {
        private String url;
        private String method = "GET";
        private Map<String, String> headers = new HashMap<>();
        private String body = "";
        private int timeout = 5000;
        
        public Builder(String url) {
            this.url = url;
        }
        
        public Builder method(String method) {
            this.method = method;
            return this;
        }
        
        public Builder header(String key, String value) {
            this.headers.put(key, value);
            return this;
        }
        
        public Builder body(String body) {
            this.body = body;
            return this;
        }
        
        public Builder timeout(int timeout) {
            this.timeout = timeout;
            return this;
        }
        
        public HttpRequest build() {
            return new HttpRequest(this);
        }
    }
}

// Использование (очень читаемо!)
HttpRequest request = new HttpRequest.Builder("https://api.example.com/users")
    .method("POST")
    .header("Content-Type", "application/json")
    .header("Authorization", "Bearer token")
    .body("{\"name\": \"John\"}")
    .timeout(10000)
    .build();

5. Strategy (Стратегия)

Позволяет выбирать алгоритм во время выполнения. Часто используется с if-else.

// Без паттерна (плохо)
public double calculateDiscount(User user) {
    if (user.isVIP()) {
        return user.getTotalSpent() * 0.20; // 20% скидка
    } else if (user.isPremium()) {
        return user.getTotalSpent() * 0.10; // 10% скидка
    } else {
        return user.getTotalSpent() * 0.05; // 5% скидка
    }
}

// С паттерном (хорошо)
interface DiscountStrategy {
    double calculate(double amount);
}

class VIPDiscountStrategy implements DiscountStrategy {
    public double calculate(double amount) {
        return amount * 0.20;
    }
}

class PremiumDiscountStrategy implements DiscountStrategy {
    public double calculate(double amount) {
        return amount * 0.10;
    }
}

class RegularDiscountStrategy implements DiscountStrategy {
    public double calculate(double amount) {
        return amount * 0.05;
    }
}

public class DiscountCalculator {
    private DiscountStrategy strategy;
    
    public void setStrategy(DiscountStrategy strategy) {
        this.strategy = strategy;
    }
    
    public double applyDiscount(double amount) {
        return strategy.calculate(amount);
    }
}

// Использование
DiscountCalculator calculator = new DiscountCalculator();
if (user.isVIP()) {
    calculator.setStrategy(new VIPDiscountStrategy());
} else if (user.isPremium()) {
    calculator.setStrategy(new PremiumDiscountStrategy());
}

double discount = calculator.applyDiscount(user.getTotalSpent());

Рейтинг распространённости в реальных проектах

1. Singleton                    ⭐⭐⭐⭐⭐ (везде)
2. Dependency Injection         ⭐⭐⭐⭐⭐ (Spring, везде)
3. Factory                      ⭐⭐⭐⭐⭐ (очень часто)
4. Builder                      ⭐⭐⭐⭐ (частые объекты)
5. Strategy                     ⭐⭐⭐⭐ (алгоритмы)
6. Observer                     ⭐⭐⭐ (события)
7. Adapter                      ⭐⭐⭐ (интеграции)
8. Decorator                    ⭐⭐ (расширения)
9. Template Method              ⭐⭐ (базовые классы)
10. Proxy                       ⭐⭐ (кеширование, логирование)

Когда НЕ использовать паттерны

Важное правило: паттерны — это инструменты, не цель!

  • ❌ Не добавляй паттерны "на будущее"
  • ❌ Не усложняй код простых объектов
  • ✅ Используй паттерны, когда видишь конкретную проблему
  • ✅ Рефакторь в паттерн, когда код становится сложным

Вывод: Singleton, DI, Factory и Builder — это основные паттерны, которые ты встретишь в каждом Java проекте. Остальные используются реже, но важно их знать для решения специфических проблем.

Какой знаешь самый распространенный паттерн? | PrepBro