Patterns. Паттерн Prototype. Реализация схемы на C++

Паттерн Prototype. Реализация схемы на C++


Содержание


Поиск на других ресурсах:

1. Общие сведения. Назначение. Отношения

Паттерн Prototype относится к паттернам, порождающим объекты. Паттерн позволяет создавать объекты разных типов с помощью объекта-прототипа. Этот объект возвращает копию конкретного объекта данного типа.

Структура паттерна Prototype изображена на рисунке 1.

Паттерн Prototype. Структурная схема

Рисунок 1. Структура паттерна Prototype

Отношение: клиент запрашивает прототип, чтобы получить его копию.

 

2. Применение

Паттерн Prototype целесообразно применять в следующих случаях.

  1. Когда создание и представление конечных продуктов не влияет на систему в целом.
  2. Экземпляры классов продуктов должны быть определены на этапе выполнения с помощью полиморфизма.
  3. Когда есть лишним создание иерархий классов или их фабрик, которые параллельны к иерархии классов-продуктов.
  4. Если нужно, чтобы объект класса мог находиться в одном из нескольких разных состояний. В этом случае создается соответствующее количество прототипов и реализуется их клонирование.

 

3. Участники паттерна. Пример программы на языке C++. Реализация структуры (рисунок 1)

В примере реализован паттерн Prototype, структура которого изображена на рисунке 1.

Участниками паттерна являются следующие классы:

  • Prototype – задает интерфейс для клонирования самого себя;
  • ConcretePrototype – реализует операцию (метод) клонирования себя;
  • Client – с помощью прототипа (prototype) задает запрос на создание нового объекта для клонирования самого себя. В программе клиентом выступает функция main().
#include <iostream>
using namespace std;

// Паттерн Prototype - реализация структуры

// Абстрактный класс прототипа,
// подклассы этого класса будут клонировать сами себя
class Prototype abstract
{
public:
  virtual Prototype* Clone() abstract;

  // Дополнительный метод вывода информации о классе
  virtual void Print(string) abstract;
};

// Классы конкретных прототипов
// Конкретный прототип 1
class ConcretePrototype1 : public Prototype
{
private:
  string data; // данные класса

public:
  // Конструктор
  ConcretePrototype1(string data) : data(data)
  { }

  Prototype* Clone() override
  {
    // Создать копию в памяти
    Prototype* p = new ConcretePrototype1(data);

    // Вернуть копию
    return p;
  }

  // Метод вывода информации о классе
  void Print(string msg) override
  {
    cout << msg << " => " << data << endl;
  }
};

// Конкретный прототип 2
class ConcretePrototype2 : public Prototype
{
private:
  string data; // данные класса

public:
  // Конструктор
  ConcretePrototype2(string data) : data(data)
  { }

  // Метод клонирования
  virtual Prototype* Clone() override
  {
    // Создать копию в памяти
    Prototype* p = new ConcretePrototype2(data);

    // Вернуть копию
    return p;
}

  // Метод вывода информации о классе
  void Print(string msg) override
  {
    cout << msg << " => " << data << endl;
  }
};

void main()
{
  // Клиентский код
  // Ввести номер класса-прототипа
  int numPrototype;
  cout << "numPrototype = ";
  cin >> numPrototype;

  Prototype* p = nullptr;

  // В зависимости от numPrototype получить соответствующую копию
  if (numPrototype == 1)
  {
    // Создать объект прототипа
    ConcretePrototype1 prototype1("prototype1");

    // Получить копию
    p = prototype1.Clone();
  }
  else
  {
    // Создать объект прототипа
    ConcretePrototype2 prototype2("prototype2");
    p = prototype2.Clone();
  }

  // Вивести информацию об объекте прототипе
  p->Print("p");

  // Освободить ранее выделенную память
  if (p)
    delete p;
}

 

4. Результаты

Результаты использования паттерна Prototype дают следующие преимущества:

  • паттерн скрывает от клиента конкретные классы продуктов. Это уменьшает количество имен, известных клиенту;
  • паттерн дает возможность клиенту работать с узкоспециализированными классами без дополнительных модификаций;
  • добавление и удаление продуктов может происходить во время выполнения. Здесь у клиента появляется дополнительная гибкость по сравнению с другими порождающими паттернами;
  • новые объекты создаются за счет изменения их поведения (изменение значений переменных объекта), а не за счет определения новых классов. Иными словами, на основе уже существующих классов создаются экземпляры новых видов клиентских объектов;
  • существует возможность определения новых объектов путем изменения структуры. Это построение объектов из разных составляющих с помощью клонирования;
  • уменьшение количества подклассов по сравнению с другими паттернами (Factory Method, Abstract Factory);
  • с помощью классов происходит динамическое конфигурирование приложения. Классы подгружаются в приложение во время выполнения.

Недостатком паттерна считается сложность реализации Clone() в некоторых случаях. Примером может служить наличие других подобъектов в данном объекте.

 

5. Реализация

При реализации паттерна Prototype можно выделить следующие главные вопросы.

  1. Использование диспетчера прототипов. Здесь имеется в виду ведение реестра прототипов для использования клиентами. Клиенты хранят прототипы в реестре и извлекают их из него на основе заданного ключа.
  2. Сложность реализации метода Clone() в случае, если объект является сложной структурой с циклическими ссылками. Здесь важно выполнить глубокое копирование элементов, входящих в структуру сложного объекта. При этом следует учитывать такую же последовательность шагов при освобождении копии объекта.
  3. Инициализация клона значениями. Здесь возможны ситуации, когда для разных клонированных объектов нужно получать разные значения параметров.

 


Связанные темы