Patterns. The Prototype pattern. Implementation of structure in C++

The Prototype pattern. Implementation of structure in C++


Contents


Search other resources:

1. General information. Purpose. Relations

The Prototype pattern refers to patterns that produce objects. The pattern allows you to create objects of different types using a prototype object. This object returns a copy of a specific object of this type.

The Prototype pattern refers to patterns that generate objects. The pattern allows you to create objects of different types using a prototype object. This object returns a copy of a specific object of this type.

The structure of the Prototype pattern is shown in Figure 1.

The structure of Prototype pattern

Figure 1. The structure of Prototype pattern

Relation: The client requests a prototype to receive a copy of it.

 

2. Usage

The Prototype pattern is advisable to use in the following cases.

  1. When the creation and presentation of final products does not affect the system as a whole.
  2. Instances of product classes must be defined at runtime using polymorphism.
  3. When it is superfluous to create class hierarchies or their factories, which are parallel to the product class hierarchy.
  4. If you need a class object to be in one of several different states. In this case, an appropriate number of prototypes are created and their cloning is implemented.

 

3. Participants of the pattern. An example program in C++. Implementation of the structure (Figure 1)

The example implements the Prototype pattern, the structure of which is shown in Figure 1.

The participants of the pattern are the following classes:

  • Prototype – specifies the interface for cloning itself;
  • ConcretePrototype – implements the operation (method) of cloning itself;
  • Client – using a prototype, specifies a request to create a new object for cloning itself. In the program, the main() function is the client.
#include <iostream>
using namespace std;

// Prototype pattern - implementation of the structure

// Abstract prototype class,
// subclasses of this class will clone themselves
class Prototype abstract
{
public:
  virtual Prototype* Clone() abstract;

  // Additional method to display class information
  virtual void Print(string) abstract;
};

// Concrete prototype classes
// Concrete prototype 1
class ConcretePrototype1 : public Prototype
{
private:
  string data; // class data

public:
  // Constructor
  ConcretePrototype1(string data) : data(data)
  { }

  Prototype* Clone() override
  {
    // Create a copy in memory
    Prototype* p = new ConcretePrototype1(data);

    // return copy
    return p;
  }

  // Method for displaying class information
  void Print(string msg) override
  {
    cout << msg << " => " << data << endl;
  }
};

// Concrete prototype 2
class ConcretePrototype2 : public Prototype
{
private:
  string data; // the data of class

public:
  // Constructor
  ConcretePrototype2(string data) : data(data)
  { }

  // Clone method
  virtual Prototype* Clone() override
  {
    // Create copy in memory
    Prototype* p = new ConcretePrototype2(data);

    // Return copy
    return p;
  }

  // Method for displaying information about class
  void Print(string msg) override
  {
    cout << msg << " => " << data << endl;
  }
};

void main()
{
  // Client code
  // Enter the prototype class number
  int numPrototype;
  cout << "numPrototype = ";
  cin >> numPrototype;

  Prototype* p = nullptr;

  // Depending on numPrototype get the corresponding copy
  if (numPrototype == 1)
  {
    // Create the prototype object
    ConcretePrototype1 prototype1("prototype1");

    // Get the copy
    p = prototype1.Clone();
  }
  else
  {
    // Create the prototype object
    ConcretePrototype2 prototype2("prototype2");
    p = prototype2.Clone();
  }

  // Enter information about the prototype object
  p->Print("p");

  // Free previously allocated memory
  if (p)
    delete p;
}

 

4. Result

The results of using the Prototype pattern provide the following benefits:

  • the pattern hides specific product classes from the client. This reduces the number of names known to the client;
  • the pattern allows the client to work with highly specialized classes without additional modifications;
  • adding and removing of products can occur at runtime. Here the client has additional flexibility compared to other generative patterns;
  • new objects are created by changing their behavior (changing the values of object variables), rather than by defining new classes. In other words, instances of new types of client objects are created based on existing classes;
  • it is possible to define new objects by changing the structure. This is the construction of objects from different components using cloning;
  • reduction in the number of subclasses compared to other patterns (Factory Method, Abstract Factory);
  • using classes, the application is dynamically configured. Classes are loaded into the application at runtime.

The disadvantage of the pattern is the complexity of implementing Clone() in some cases.

The disadvantage of the pattern is the complexity of implementing Clone() in some cases. An example would be the presence of other subobjects in a given object.

 

5. Implementation

When implementing the Prototype pattern, the following main issues can be highlighted.

  1. Using the prototype manager. This refers to maintaining an inventory of prototypes for use by clients. Clients store prototypes in a registry and retrieve them from it based on a given key.
  2. The complexity of implementing the Clone() method if the object is a complex structure with cyclic references. Here it is important to perform a deep copy of the elements included in the structure of a complex object. In this case, you should consider the same sequence of steps when freeing a copy of an object.
  3. Initializing the clone with values. There may be situations where you need to get different parameter values for different cloned objects.

 


Related topics