Прототип

Паттерны проектирования / Порождающие паттерны
image

//Prototype: a pointer to a function plays the virtual clone()
typedef struct Shape {
    const char *color;
    struct Shape *(*clone)(const struct Shape *self);
} Shape;

//ConcretePrototype: the base struct is the first field
typedef struct {
    Shape base;
} Square;

//only the concrete type knows its size, so it makes the copy;
//assigning a struct copies all its fields
Shape *squareClone(const Shape *self) {
    Square *copy = malloc(sizeof *copy);
    *copy = *(const Square *)self;
    return &copy->base;
}

//Client
typedef struct {
    const Shape *shape;
} ShapeMaker;

Shape *makeShape(const ShapeMaker *maker) {
    return maker->shape->clone(maker->shape);
}

Square square = {{"Red", squareClone}};
ShapeMaker maker = {&square.base};

Shape *square1 = makeShape(&maker);
Square *square2 = (Square *)makeShape(&maker);
//square1->color is "Red"
//square2->base.color is "Red"
bool same = square1 == &square2->base;
//same is false: each call makes a new copy

printf("color1 is %s\n", square1->color);
printf("color2 is %s\n", square2->base.color);
printf("same is %s\n", same ? "true" : "false");
free(square1);
free(square2);


Описывает виды создаваемых объектов с помощью прототипа и создает новые объекты путем его копирования.
Read more

Задача. В графическом редакторе есть палитра готовых фигур, и у каждой свои цвет, размер и рамка. Когда пользователь перетаскивает фигуру на страницу, программа должна сделать точно такую же новую фигуру. Если код пользуется конструктором, ему приходится знать точный класс и вручную копировать каждую настройку. Тогда каждый новый вид фигуры меняет этот код.

Идея. Прототип - это готовый объект, который умеет себя копировать. У него один метод копирования, часто он называется clone. Клиент держит прототип и просит у него копии. Конкретный класс клиент не называет и не знает, какие поля копируются. Копия начинает с теми же данными, что у оригинала, а дальше два объекта живут независимо.

Как читать пример. Прототип - это фигура с одним значением, например цветом или числом сторон. В большинстве языков объект-клиент держит один прототип, а новые фигуры получает только одним способом - просит у него копию. Вывод показывает, что у копий то же значение, что у прототипа. Некоторые примеры показывают ещё, что копия - отдельный объект или что изменение копии не трогает прототип. В языках, где значения никогда не меняются, ничего не копируется: новый вариант - это тот же образец с одним изменённым полем.

Когда применять. Прототип нужен, когда объект дорого подготовить, а похожих объектов требуется много. Он помогает и тогда, когда класс создаваемого объекта становится известен только во время работы программы. Для простых объектов с немногими полями он ни к чему: конструктор проще.

Частая ошибка. Написать метод копирования только в базовом классе, так что он всегда создаёт базовый объект. Копия конкретного прототипа тогда теряет свой класс. Каждый конкретный прототип должен создавать объект своего класса.