← Назад к вопросам
Приведи пример использования Prototype
3.0 Senior🔥 121 комментариев
#Spring Framework
Комментарии (1)
🐱
claude-haiku-4.5PrepBro AI22 мар. 2026 г.(ред.)
Ответ сгенерирован нейросетью и может содержать ошибки
# Пример использования паттерна Prototype
Паттерн Prototype позволяет создавать новые объекты путём копирования существующего объекта (прототипа) вместо создания с нуля. Это полезно когда создание объекта дорого, а клонирование дешево.
Основная идея
Без Prototype:
Создаем объект → Инициализируем поля → Готово
↓ дорого и медленно
С Prototype:
Возьми готовый прототип → Клонируй → Готово
↓ быстро и просто
Реальный пример: Документы в системе
Проблема
// ❌ ПЛОХО - создание документов с нуля
public class DocumentFactory {
public Document createContractDocument(String clientName) {
Document doc = new Document();
// Долгая инициализация
doc.setHeader("ДОГОВОР");
doc.setTitle("Договор оказания услуг");
doc.setAuthor("Компания XYZ");
doc.setPageNumber(true);
doc.setNumbering(true);
// Добавление множества разделов
doc.addSection("1. Предмет договора");
doc.addSection("2. Стоимость услуг");
doc.addSection("3. Сроки выполнения");
doc.addSection("4. Ответственность сторон");
doc.addSection("5. Заключительные положения");
// Установка форматирования
doc.setFont(new Font("Times New Roman", 12));
doc.setLineSpacing(1.5);
doc.setMargins(2, 2, 2, 2);
// Наконец, персонализируем для клиента
doc.setClientName(clientName);
return doc; // После ВСЕЙ этой работы!
}
}
// Каждый раз создание документа — медленно!
Document contract1 = factory.createContractDocument("ООО Компания 1");
Document contract2 = factory.createContractDocument("ООО Компания 2");
Document contract3 = factory.createContractDocument("ООО Компания 3");
// Все 3 инициализации выполнены заново!
Решение с Prototype
// Интерфейс для клонирования
public interface Prototype {
Prototype clone();
}
// Документ с поддержкой клонирования
public class Document implements Prototype {
private String header;
private String title;
private String author;
private List<String> sections;
private Font font;
private double lineSpacing;
private Margins margins;
private String clientName;
@Override
public Document clone() {
try {
Document cloned = (Document) super.clone();
// Глубокое копирование для коллекций
cloned.sections = new ArrayList<>(this.sections);
// Глубокое копирование для объектов
cloned.font = new Font(this.font.getName(), this.font.getSize());
cloned.margins = new Margins(this.margins.getTop(),
this.margins.getBottom(),
this.margins.getLeft(),
this.margins.getRight());
return cloned;
} catch (CloneNotSupportedException e) {
throw new RuntimeException(e);
}
}
// getters и setters
public void setClientName(String clientName) {
this.clientName = clientName;
}
}
// ✅ ХОРОШО - создание с использованием прототипа
public class DocumentPrototypeFactory {
// Прототипы
private Document contractPrototype;
private Document reportPrototype;
private Document invoicePrototype;
public DocumentPrototypeFactory() {
// Инициализируем прототипы один раз!
initializePrototypes();
}
private void initializePrototypes() {
// Создаём прототип контракта один раз
contractPrototype = new Document();
contractPrototype.setHeader("ДОГОВОР");
contractPrototype.setTitle("Договор оказания услуг");
contractPrototype.setAuthor("Компания XYZ");
contractPrototype.setPageNumber(true);
contractPrototype.setNumbering(true);
contractPrototype.addSection("1. Предмет договора");
contractPrototype.addSection("2. Стоимость услуг");
contractPrototype.addSection("3. Сроки выполнения");
contractPrototype.addSection("4. Ответственность сторон");
contractPrototype.addSection("5. Заключительные положения");
contractPrototype.setFont(new Font("Times New Roman", 12));
contractPrototype.setLineSpacing(1.5);
contractPrototype.setMargins(2, 2, 2, 2);
}
// Создание документа из прототипа
public Document createContractDocument(String clientName) {
// Клонируем прототип (быстро!)
Document doc = contractPrototype.clone();
// Только персонализируем
doc.setClientName(clientName);
return doc;
}
}
// Использование
DocumentPrototypeFactory factory = new DocumentPrototypeFactory(); // Инициализация один раз
Document contract1 = factory.createContractDocument("ООО Компания 1"); // Быстро!
Document contract2 = factory.createContractDocument("ООО Компания 2"); // Быстро!
Document contract3 = factory.createContractDocument("ООО Компания 3"); // Быстро!
Практический пример: Конфигурация серверов
// Конфигурация сервера
public class ServerConfig implements Prototype {
private String hostname;
private int port;
private String environment; // prod, staging, dev
private List<String> modules;
private Map<String, String> settings;
private SecurityPolicy securityPolicy;
@Override
public ServerConfig clone() {
try {
ServerConfig cloned = (ServerConfig) super.clone();
cloned.modules = new ArrayList<>(this.modules);
cloned.settings = new HashMap<>(this.settings);
cloned.securityPolicy = this.securityPolicy.clone();
return cloned;
} catch (CloneNotSupportedException e) {
throw new RuntimeException(e);
}
}
}
// Реестр прототипов
public class ServerConfigRegistry {
private Map<String, ServerConfig> configs = new HashMap<>();
public ServerConfigRegistry() {
// Инициализируем прототипы
initializeProdPrototype();
initializeStagingPrototype();
initializeDevPrototype();
}
private void initializeProdPrototype() {
ServerConfig prodConfig = new ServerConfig();
prodConfig.setEnvironment("prod");
prodConfig.setPort(443);
prodConfig.addModule("authentication");
prodConfig.addModule("database");
prodConfig.addModule("cache");
prodConfig.setSetting("max_connections", "1000");
prodConfig.setSetting("log_level", "ERROR");
prodConfig.setSecurityPolicy(new StrictSecurityPolicy());
configs.put("prod", prodConfig);
}
private void initializeStagingPrototype() {
ServerConfig stagingConfig = new ServerConfig();
stagingConfig.setEnvironment("staging");
stagingConfig.setPort(8443);
stagingConfig.addModule("authentication");
stagingConfig.addModule("database");
stagingConfig.addModule("monitoring"); // Дополнительный модуль
stagingConfig.setSetting("max_connections", "500");
stagingConfig.setSetting("log_level", "INFO");
stagingConfig.setSecurityPolicy(new MediumSecurityPolicy());
configs.put("staging", stagingConfig);
}
private void initializeDevPrototype() {
ServerConfig devConfig = new ServerConfig();
devConfig.setEnvironment("dev");
devConfig.setPort(8080);
devConfig.addModule("authentication");
devConfig.addModule("database");
devConfig.addModule("debug"); // Debug модуль
devConfig.setSetting("max_connections", "10");
devConfig.setSetting("log_level", "DEBUG");
devConfig.setSecurityPolicy(new NoSecurityPolicy());
configs.put("dev", devConfig);
}
// Создание конфига из прототипа
public ServerConfig createConfig(String environment, String hostname) {
ServerConfig prototype = configs.get(environment);
ServerConfig config = prototype.clone();
config.setHostname(hostname);
return config;
}
}
// Использование
ServerConfigRegistry registry = new ServerConfigRegistry();
// Создание конфигов для разных серверов
ServerConfig prod1 = registry.createConfig("prod", "prod-server-1.example.com");
ServerConfig prod2 = registry.createConfig("prod", "prod-server-2.example.com");
ServerConfig staging = registry.createConfig("staging", "staging.example.com");
ServerConfig dev = registry.createConfig("dev", "localhost");
// Каждый имеет свой hostname, но настройки скопированы из прототипа
System.out.println(prod1.getHostname()); // prod-server-1.example.com
System.out.println(prod1.getEnvironment()); // prod
System.out.println(prod1.getLogLevel()); // ERROR (из прототипа)
Сравнение подходов
// Вариант 1: Builder Pattern
ServerConfig config = ServerConfig.builder()
.hostname("server.com")
.environment("prod")
.port(443)
.addModule("auth")
.addModule("db")
.setSetting("timeout", "30")
.build();
// Плюсы: ясный код, контроль
// Минусы: много кода, медленнее
// Вариант 2: Prototype Pattern
ServerConfig config = registry.createConfig("prod", "server.com");
// Плюсы: быстро, переиспользование
// Минусы: нужна инициализация прототипов
Когда использовать Prototype?
✅ Создание объектов дорого:
- Сложная инициализация
- Загрузка данных с диска/сети
- Множество зависимостей
✅ Много похожих объектов:
- Копирование часто
- Почти идентичные конфигурации
- Шаблоны
✅ Изоляция от класса:
- Не нужно знать детали создания
- Просто клонируй существующий
❌ Когда НЕ использовать:
- Простые объекты с конструктором
- Клонирование медленнее чем создание
- Нет прототипов для переиспользования
Java встроенный Prototype
// В Java уже встроена поддержка
public class MyClass implements Cloneable {
@Override
public MyClass clone() throws CloneNotSupportedException {
return (MyClass) super.clone();
}
}
// Использование
MyClass original = new MyClass();
MyClass copy = original.clone();
Заключение
Prototype Pattern решает:
- Дорогое создание объектов
- Переиспользование похожих объектов
- Инкапсуляцию логики инициализации
Используется в:
- Системах конфигурации
- Документооборотных системах
- Кэшировании
- Фабриках с прототипами