19
January
2008

Паттерн Прототип (Prototype Design Pattern)

Posted in: Паттерны проектирования |

В написанных ранее статьях мы уже рассматривали паттерны создания объектов (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.



svetliy
January 21, 2008 #

Как-то не очень раскрыта суть паттерна.
1)если создание объектов (через оператор new) занимает длительный промежуток времени или требовательно к памяти;
как это понять если все равно в clone создается новый объект (вызов return new ComplicatedObject();)
2) Но рассмотрим отличный от клонирования вариант:
и в чем суть этого отличного от клонирования варианта

Я понимаю так суть паттерна прототип:
если нам необходимо получить клон(полную независимую копию экземпляра класса, где значения полей (атрибутов)совпадают с исходным, но имеют разные ссылки) объекта, то необходимо реализовать интерфейс Clonable. Метод clone класса Object просто производит копирование.

January 21, 2008 #

Спасибо за комментарий.
Постараюсь ответить на ваши вопросы.
1) Прототип может использоваться и в том случае, если создание нового объекта нетривиально для пользователя. Например, в конструкторе много параметров. Или автор класса не хочет, чтобы пользователь создавал класс через new, но конструктор нельзя делать приватным для поддержки reflection. Всякое бывает…
2) Суть примера как раз и описана в моем предыдущем ответе. ComplicatedObject в примере - это какой-то сложный объект, возможно со сложной древовидной структурой. Время его создания может быть и небольшим, но потребует много вызовов для пользователя. Например - для создания копии сильноветвящегося DOM документа вряд ли кто-то создаст новый документ и подобавляет в него элементы и текстовые ноды. Скорее сделают импорт корневой ноды в другой документ.

Насколько я понял, пример не очень прозрачный. В ближайшее время додумаю его. Еще раз спасибо.

Entry_N3
January 26, 2008 #

Всегда интересовался вопросом клонирования объектов. Но упал интерес к данному вопросу, когда узнал, что классы этих объектов должны реализовывать метод clone(), а других возможностей нет. Это так?

January 26, 2008 #

Создать объект можно еще с помощью оператора new или с помощью reflection (опять же через вызов конструктора).
А почему интерес упал?

Entry_N3
January 27, 2008 #

Упал в том смысле, что нельзя просто написать “скопируй мне вот этот объект”, например, как с массивами:

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]);
}

(хотя не отрицаю в данном случае, что массив это объект, но этот
пример не подчиняется правилу индукции на все остальные объекты)

January 27, 2008 #

Не очень понимаю. Все нормально клонируется
Результат твоего примера будет - 9,8,7,9,8,7.

Entry_N3
January 27, 2008 #

Я хотел показать, что было бы круто копировать так же просто другие объекты, как массивы в моем примере.

Victor Conovalov
February 5, 2008 #

А в чем принципиальная разница между Prototype Pattern and Copy Constructor?

ilya
July 28, 2008 #

Просто переопредели)

Leave a comment

XHTML: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <code> <em> <i> <strike> <strong>