January
2008
В написанных ранее статьях мы уже рассматривали паттерны создания объектов (Creational Design Patterns).
Так как с необходимостью создания объектов програмисты встречаются каждый день, рассмотрим еще один паттерн - Prototype (Прототип).
Паттерн Prototype позволяет создавать новые объекты на основе некоторого объекта-прототипа при этом совсем не обязательно знать как необходимый объект устроен.
Вот некоторые ситуации когда может помочь этот паттерн проектирования:
- если создание объектов (через оператор new) занимает длительный промежуток времени или требовательно к памяти;
- если создание объектов для клиента является нетривиальной задачей, например, когда объект составной;
- избежать множества фабрик для создания конкретных экземпляров классов;
- если клиент не знает специфики создания объекта.
В Java уже заложена функциональность для имплементации паттерна Прототип - интерфейс Cloneable.
Для этого достаточно объявить класс (который и будет прототипом), как реализующий Cloneable. Далее, вместо создания объектов нашего класса через оператор new, воспользуемся методом clone у ранее созданного объекта (прототипа).
Но рассмотрим отличный от клонирования вариант:
public interface Copyable {
Copyable copy();
}
public class ComplicatedObject implements Copyable {
public enum Type {
ONE, TWO
}
public ComplicatedObject copy() {
return new ComplicatedObject();
}
public void setType(Type type) {
this.type = type;
}
}
public class Test {
public static void main(String[] args) {
ComplicatedObject prototype = new ComplicatedObject();
ComplicatedObject clone = prototype.copy();
clone.setType(ComplicatedObject.Type.ONE);
}
}
Прдеоставленный выше код может быть полезен в таком случае. Если ComplicatedObject сложен для инстанциирования - имеет множество полей отвечающих за состояние - а пользователю важно только ограниченное их количество, то с помощью прототипа можно создавать объекты-копии и менять только те поля, которые важны для клиента. Подразумевается, что остальные поля имеют валидные значения.
Паттерн Prototype часто используется в связке с Composite (если объект имеет сложную реализацию), Facade (если необходимо предоставить интерфейс для прототипирования множества разнотипных объектов).
Альтернативой паттерну Прототип могут быть шаблоны Abstract Factory или Factory Method.
Жду ваших комментариев и вопросов.
9 Comments »
RSS feed for comments on this post.
Как-то не очень раскрыта суть паттерна.
1)если создание объектов (через оператор new) занимает длительный промежуток времени или требовательно к памяти;
как это понять если все равно в clone создается новый объект (вызов return new ComplicatedObject();)
2) Но рассмотрим отличный от клонирования вариант:
и в чем суть этого отличного от клонирования варианта
Я понимаю так суть паттерна прототип:
если нам необходимо получить клон(полную независимую копию экземпляра класса, где значения полей (атрибутов)совпадают с исходным, но имеют разные ссылки) объекта, то необходимо реализовать интерфейс Clonable. Метод clone класса Object просто производит копирование.
Спасибо за комментарий.
Постараюсь ответить на ваши вопросы.
1) Прототип может использоваться и в том случае, если создание нового объекта нетривиально для пользователя. Например, в конструкторе много параметров. Или автор класса не хочет, чтобы пользователь создавал класс через new, но конструктор нельзя делать приватным для поддержки reflection. Всякое бывает…
2) Суть примера как раз и описана в моем предыдущем ответе. ComplicatedObject в примере - это какой-то сложный объект, возможно со сложной древовидной структурой. Время его создания может быть и небольшим, но потребует много вызовов для пользователя. Например - для создания копии сильноветвящегося DOM документа вряд ли кто-то создаст новый документ и подобавляет в него элементы и текстовые ноды. Скорее сделают импорт корневой ноды в другой документ.
Насколько я понял, пример не очень прозрачный. В ближайшее время додумаю его. Еще раз спасибо.
Всегда интересовался вопросом клонирования объектов. Но упал интерес к данному вопросу, когда узнал, что классы этих объектов должны реализовывать метод clone(), а других возможностей нет. Это так?
Создать объект можно еще с помощью оператора new или с помощью reflection (опять же через вызов конструктора).
А почему интерес упал?
Упал в том смысле, что нельзя просто написать “скопируй мне вот этот объект”, например, как с массивами:
int arrBasic[] = new int[3];
arrBasic[0] = 9; arrBasic[1] = 8; arrBasic[2] = 7;
for(int j=0; j < arrBasic.length; j++){
System.out.println(arrBasic[j]);
}
int arrClone[] = arrBasic.clone();
for(int j=0; j < arrClone.length; j++){
System.out.println(arrClone[j]);
}
(хотя не отрицаю в данном случае, что массив это объект, но этот
пример не подчиняется правилу индукции на все остальные объекты)
Не очень понимаю. Все нормально клонируется
Результат твоего примера будет - 9,8,7,9,8,7.
Я хотел показать, что было бы круто копировать так же просто другие объекты, как массивы в моем примере.
А в чем принципиальная разница между Prototype Pattern and Copy Constructor?
Просто переопредели)