← Назад к вопросам
Для чего нужен Фабричный метод?
2.0 Middle🔥 171 комментариев
#SOLID и паттерны проектирования
Комментарии (1)
🐱
claude-haiku-4.5PrepBro AI22 мар. 2026 г.(ред.)
Ответ сгенерирован нейросетью и может содержать ошибки
# Фабричный метод (Factory Method Pattern)
Фабричный метод — это порождающий паттерн проектирования, который предоставляет интерфейс для создания объектов, но позволяет подклассам решать, какой класс инстанцировать.
Основные причины использования
1. Абстракция создания объектов
Вместо прямого использования new, клиент обращается к фабричному методу. Это скрывает детали создания:
// Без паттерна (плохо)
if (type.equals("PDF")) {
document = new PDFDocument();
} else if (type.equals("WORD")) {
document = new WordDocument();
}
// С паттерном (хорошо)
Document document = DocumentFactory.createDocument(type);
2. Слабая связанность (Low Coupling)
Клиент зависит от интерфейса, а не от конкретных реализаций:
// Интерфейс
public interface Document {
void open();
void save();
}
// Конкретные классы
public class PDFDocument implements Document {
@Override
public void open() { /* логика открытия PDF */ }
@Override
public void save() { /* логика сохранения PDF */ }
}
public class WordDocument implements Document {
@Override
public void open() { /* логика открытия WORD */ }
@Override
public void save() { /* логика сохранения WORD */ }
}
// Фабрика
public class DocumentFactory {
public static Document createDocument(String type) {
switch (type.toLowerCase()) {
case "pdf":
return new PDFDocument();
case "word":
return new WordDocument();
default:
throw new IllegalArgumentException("Unknown type: " + type);
}
}
}
// Использование
Document doc = DocumentFactory.createDocument("pdf");
doc.open();
3. Централизованное управление инстанцированием
Вся логика создания в одном месте, легче отслеживать и модифицировать:
public class DatabaseFactory {
private static Map<String, DataSource> pool = new ConcurrentHashMap<>();
public static DataSource createDataSource(String dbType) {
return pool.computeIfAbsent(dbType, key -> {
// Сложная логика инициализации БД
switch (key) {
case "PostgreSQL":
return createPostgresDataSource();
case "MySQL":
return createMysqlDataSource();
default:
throw new IllegalArgumentException("Unknown DB: " + key);
}
});
}
private static DataSource createPostgresDataSource() {
HikariConfig config = new HikariConfig();
config.setJdbcUrl("jdbc:postgresql://localhost:5432/mydb");
config.setUsername("user");
config.setPassword("pass");
config.setMaximumPoolSize(10);
return new HikariDataSource(config);
}
private static DataSource createMysqlDataSource() {
// аналогично для MySQL
return new HikariDataSource(config);
}
}
4. Условное создание с параметрами
Фабрика может выбирать реализацию на основе параметров или конфигурации:
public class PaymentProcessorFactory {
public static PaymentProcessor create(String provider) {
switch (provider) {
case "STRIPE":
return new StripePaymentProcessor(
System.getenv("STRIPE_KEY")
);
case "PAYPAL":
return new PayPalPaymentProcessor(
System.getenv("PAYPAL_KEY")
);
case "MOCK": // для тестирования
return new MockPaymentProcessor();
default:
throw new IllegalArgumentException("Unknown provider: " + provider);
}
}
}
// Использование
PaymentProcessor processor = PaymentProcessorFactory.create(
System.getenv("PAYMENT_PROVIDER")
);
processor.process(amount);
5. Простое расширение (Open/Closed Principle)
Добавить новый тип можно, не изменяя существующий код (в идеале):
// Если используем рефлексию или конфигурацию
public class ConfigurableFactory {
private Map<String, Class<?>> registry = new HashMap<>();
public void register(String type, Class<?> cls) {
registry.put(type, cls);
}
public Object create(String type) throws Exception {
Class<?> cls = registry.get(type);
if (cls == null) throw new IllegalArgumentException("Unknown type");
return cls.getDeclaredConstructor().newInstance();
}
}
// Использование
ConfigurableFactory factory = new ConfigurableFactory();
factory.register("pdf", PDFDocument.class);
factory.register("word", WordDocument.class);
factory.register("excel", ExcelDocument.class); // легко добавить новый
6. Spring Framework пример
Spring использует фабричные методы везде:
@Configuration
public class AppConfig {
@Bean
public DataSource dataSource() {
HikariConfig config = new HikariConfig();
config.setJdbcUrl("jdbc:postgresql://localhost/db");
return new HikariDataSource(config);
}
@Bean
public UserRepository userRepository(DataSource ds) {
return new JdbcUserRepository(ds);
}
@Bean
public UserService userService(UserRepository repo) {
return new UserService(repo);
}
}
Когда использовать
- Класс не может знать точный тип создаваемых объектов
- Нужна гибкость в выборе реализации
- Создание сложного объекта требует дополнительной логики
- Нужно управлять пулом объектов
- Необходимо логирование/аудит создания объектов
Резюме
Фабричный метод нужен для:
- Слабой связанности между классами
- Абстракции процесса создания объектов
- Централизованного управления инстанцированием
- Условного выбора реализации
- Упрощения расширения функционала