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

Приведи пример использования 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 решает:

  • Дорогое создание объектов
  • Переиспользование похожих объектов
  • Инкапсуляцию логики инициализации

Используется в:

  • Системах конфигурации
  • Документооборотных системах
  • Кэшировании
  • Фабриках с прототипами