← Назад к вопросам
При обращении к чему Prototype будет создавать новый объект
2.0 Middle🔥 101 комментариев
#Spring Framework
Комментарии (1)
🐱
claude-haiku-4.5PrepBro AI22 мар. 2026 г.(ред.)
Ответ сгенерирован нейросетью и может содержать ошибки
# При обращении к чему Prototype будет создавать новый объект
Это вопрос про то, когда Prototype паттерн срабатывает и создаёт новые объекты. Важно понимать момент, когда происходит клонирование.
Основной момент: clone() вызов
Прототип создаёт новый объект только когда явно вызывается метод clone():
prototype.clone() // ← ВОТ ЗДЕСЬ создаётся новый объект
Практический пример
Конфигурация
public class AppConfig implements Cloneable {
private String database;
private int maxConnections;
private String logLevel;
private List<String> modules;
@Override
public AppConfig clone() {
try {
AppConfig cloned = (AppConfig) super.clone();
// Глубокое копирование для список
cloned.modules = new ArrayList<>(this.modules);
return cloned; // ← НОВЫЙ объект создан здесь
} catch (CloneNotSupportedException e) {
throw new RuntimeException(e);
}
}
}
// ОБратка к свойствам прототипа - новый объект НЕ создаётся
AppConfig prototype = new AppConfig();
prototype.setDatabase("PostgreSQL");
prototype.setMaxConnections(50);
prototype.setLogLevel("INFO");
prototype.addModule("auth");
// Все эти обращения изменяют ТОТ ЖЕ прототип
System.out.println(prototype.getDatabase()); // "PostgreSQL" - не clone
System.out.println(prototype.getLogLevel()); // "INFO" - не clone
// Только clone() создаёт НОВЫЙ объект
AppConfig config1 = prototype.clone(); // ← Новый объект создан
AppConfig config2 = prototype.clone(); // ← Новый объект создан
AppConfig config3 = prototype.clone(); // ← Новый объект создан
// config1, config2, config3 - разные объекты с одинаковыми данными
config1 != config2; // true (разные объекты в памяти)
config1.equals(config2); // true (одинаковые данные)
Фабрика с прототипом
public class ConfigFactory {
private AppConfig prodPrototype;
private AppConfig devPrototype;
public ConfigFactory() {
// Инициализируем прототипы один раз
initializePrototypes();
}
private void initializePrototypes() {
prodPrototype = new AppConfig();
prodPrototype.setDatabase("prod.db");
prodPrototype.setMaxConnections(100);
prodPrototype.setLogLevel("ERROR");
devPrototype = new AppConfig();
devPrototype.setDatabase("dev.db");
devPrototype.setMaxConnections(10);
devPrototype.setLogLevel("DEBUG");
}
// ← При обращении к этому методу создаётся новый объект
public AppConfig createProdConfig() {
return prodPrototype.clone(); // ← НОВЫЙ объект
}
public AppConfig createDevConfig() {
return devPrototype.clone(); // ← НОВЫЙ объект
}
}
// Использование
ConfigFactory factory = new ConfigFactory();
// Каждый вызов создаёт НОВЫЙ объект
AppConfig app1 = factory.createProdConfig(); // Новый объект
AppConfig app2 = factory.createProdConfig(); // Новый объект
AppConfig app3 = factory.createProdConfig(); // Новый объект
app1 != app2; // true (разные объекты)
app1.getDatabase().equals(app2.getDatabase()); // true (одинаковые данные)
Жизненный цикл Prototype
Шаг 1: Инициализация (один раз)
┌──────────────────────────────────────────────┐
│ Создание прототипа │
│ prototype = new AppConfig() │
│ prototype.setDatabase("prod") │
│ prototype.setMaxConnections(100) │
│ prototype.setLogLevel("ERROR") │
│ │
│ Объект в памяти: 1 экземпляр │
│ Используется для клонирования │
└──────────────────────────────────────────────┘
Шаг 2: Клонирование (много раз)
┌──────────────────────────────────────────────┐
│ config1 = prototype.clone() ← НОВЫЙ объект │
│ config2 = prototype.clone() ← НОВЫЙ объект │
│ config3 = prototype.clone() ← НОВЫЙ объект │
│ │
│ Объектов в памяти: 4 экземпляра │
│ (1 прототип + 3 клона) │
└──────────────────────────────────────────────┘
Сравнение подходов
Без Prototype (каждый раз новое создание)
public AppConfig createProdConfig() {
AppConfig config = new AppConfig(); // ← НОВОЕ создание
config.setDatabase("prod");
config.setMaxConnections(100);
config.setLogLevel("ERROR");
config.addModule("auth");
config.addModule("db");
config.addModule("cache");
// ... ещё 20 операций
return config;
}
// Каждый вызов - полная инициализация
AppConfig app1 = createProdConfig(); // Медленно
AppConfig app2 = createProdConfig(); // Медленно
AppConfig app3 = createProdConfig(); // Медленно
С Prototype (один раз инициализация)
// Инициализация один раз
private AppConfig prodPrototype = new AppConfig();
prodPrototype.setDatabase("prod");
prodPrototype.setMaxConnections(100);
prodPrototype.setLogLevel("ERROR");
prodPrototype.addModule("auth");
prodPrototype.addModule("db");
prodPrototype.addModule("cache");
// Каждый вызов - просто клонирование
public AppConfig createProdConfig() {
return prodPrototype.clone(); // Быстро
}
// Использование
AppConfig app1 = createProdConfig(); // Быстро
AppConfig app2 = createProdConfig(); // Быстро
AppConfig app3 = createProdConfig(); // Быстро
Реестр прототипов
public class PrototypeRegistry {
private Map<String, Object> prototypes = new HashMap<>();
public void registerPrototype(String key, Object prototype) {
prototypes.put(key, prototype);
}
// При обращении к этому методу - создаётся НОВЫЙ объект
public <T> T createObject(String key) {
T prototype = (T) prototypes.get(key);
if (prototype == null) {
throw new IllegalArgumentException("Prototype not found: " + key);
}
// Клонируем если это Cloneable
if (prototype instanceof Cloneable) {
try {
return (T) prototype.getClass()
.getMethod("clone")
.invoke(prototype); // ← НОВЫЙ объект создан
} catch (Exception e) {
throw new RuntimeException(e);
}
}
return prototype; // Если не Cloneable - возвращаем сам прототип
}
}
// Использование
PrototypeRegistry registry = new PrototypeRegistry();
// Регистрируем прототипы (один раз)
AppConfig prodPrototype = new AppConfig();
prodPrototype.setDatabase("prod");
registry.registerPrototype("prod", prodPrototype);
AppConfig devPrototype = new AppConfig();
devPrototype.setDatabase("dev");
registry.registerPrototype("dev", devPrototype);
// Создание объектов (много раз)
AppConfig config1 = registry.createObject("prod"); // ← НОВЫЙ
AppConfig config2 = registry.createObject("prod"); // ← НОВЫЙ
AppConfig config3 = registry.createObject("dev"); // ← НОВЫЙ
config1 != config2; // true (разные объекты)
config1 != config3; // true (разные объекты)
Диаграмма создания объектов
Прототип в памяти:
┌─────────────────────────────┐
│ AppConfig (prototype) │
│ ├─ database: "prod" │
│ ├─ maxConnections: 100 │
│ └─ logLevel: "ERROR" │
│ │
│ Адрес в памяти: 0x1000 │
└─────────────────────────────┘
После clone() #1:
┌─────────────────────────────┐
│ AppConfig (prototype) │ (остаётся неизменным)
│ ├─ database: "prod" │
│ ├─ maxConnections: 100 │
│ └─ logLevel: "ERROR" │
│ Адрес: 0x1000 │
└─────────────────────────────┘
┌─────────────────────────────┐
│ AppConfig (clone #1) │ ← НОВЫЙ объект
│ ├─ database: "prod" │
│ ├─ maxConnections: 100 │
│ └─ logLevel: "ERROR" │
│ Адрес: 0x2000 │
└─────────────────────────────┘
После clone() #2:
┌─────────────────────────────┐
│ AppConfig (clone #2) │ ← ЕЩЁ НОВЫЙ объект
│ ├─ database: "prod" │
│ ├─ maxConnections: 100 │
│ └─ logLevel: "ERROR" │
│ Адрес: 0x3000 │
└─────────────────────────────┘
Важно: Поверхностное vs глубокое копирование
public class ConfigWithList implements Cloneable {
private List<String> modules;
// ❌ ПЛОХО - поверхностное копирование
@Override
public ConfigWithList cloneShallow() {
try {
return (ConfigWithList) super.clone();
// modules указывает на ТОТ ЖЕ объект List!
} catch (CloneNotSupportedException e) {
throw new RuntimeException(e);
}
}
// ✅ ХОРОШО - глубокое копирование
@Override
public ConfigWithList clone() {
try {
ConfigWithList cloned = (ConfigWithList) super.clone();
// Создаём НОВЫЙ List с копией данных
cloned.modules = new ArrayList<>(this.modules);
return cloned; // ← Новый объект со своим List
} catch (CloneNotSupportedException e) {
throw new RuntimeException(e);
}
}
}
// Демонстрация
ConfigWithList prototype = new ConfigWithList();
prototype.addModule("auth");
ConfigWithList clone1 = prototype.clone(); // Новый объект
ConfigWithList clone2 = prototype.clone(); // Новый объект
// Изменение clone1 не влияет на clone2
clone1.addModule("db");
clone1.getModules().size(); // 2 ("auth", "db")
clone2.getModules().size(); // 1 ("auth") - не изменился!
Заключение
Новый объект создаётся при обращении к:
prototype.clone()- явное клонированиеfactory.createObject()- в фабрике, которая вызывает clone()registry.createObject("key")- в реестре, который вызывает clone()
НЕ создаётся новый объект при обращении к:
prototype.getProperty()- просто чтениеprototype.setProperty()- изменение прототипа- Любые другие методы - используется ТОТ ЖЕ объект
Ключевой момент: clone() - единственный способ создать новый объект в Prototype паттерне.