Prototype by

Specify the kinds of objects to create using a prototypical instance, and createnew objects by copying this prototype.

Motivation

It is a well known fact, that most people in the world have created a version of Minecraft. Although we are not disheartened by this and, like most people, decide to create our own as well. To stand out we will have a two unique features that some of the other implementations don’t yet have.

Firstly we also have structures. A structure is created by placing a cornerstone. A special block that saves all the blocks that are placed in vicinity of this block. When the player picks the block back up again the structure will be saved. So if a player is set out to create a village where everyone lives in a giant structure, the player can simply place a cornerstone, build a mushroom around it and pick up the cornerstone. The following mushroom houses can be created by placing complete structures at a time.

To implement this feature we could create an array of block types. When a cornerstone is placed we will save the types into this array. To recreate the structure we can send these types to the block factory and have it instantiate the whole structure. So far so good now on to the next feature.

Secondly we will have an in game block designer. In the designer a player is able to customize the blocks by drawing on them.

This feature on its own is also quite straightforward. We could have a custom block type factory that holds all the different textures and different features of the custom blocks. While possible this will quickly get quite complex and most likely we have already broken our first feature.

Alternatively we could use the prototype pattern. We define a Clone() method in each block, so that we can recreate an exact copy of a block as long as we have a reference to a block of given type. We also add clone method to the structure, which iterates over the array of blocks and calls the Clone() method on each one.

If our structure knows how to clone itself and each block as well, we have already implemented all both of the features. Furthermore when we add completely new kinds of objects into the game, we can also use them as part of structures as long as they implement the Clone() method, without having to go back and fix the code in structure class.

Structure

Participants

  • Prototype

    • Declares interface for cloning. If a concrete object implements this interface, then client is aware, that the object can be cloned.

  • Client

    • Creates new object, by calling the clone method on prototype.

  • Concrete Prototype

    • Implements the method for cloning itself, which also returns reference to the new object.

Example Uses

Use the prototype pattern when:

  • The system should be independent of how its objects are created, composed, and represented

  • The classes to be instantiated are specified at run-time, for example, by dynamic loading or use of the type object pattern;

  • You want to avoid building a class hierarchy of factories that parallels the class hierarchy of products

  • The system supports cloning or objects are not too complex. Keep in mind that each class must implement a clone method. This can be especially difficult, if the classes should include circular references.

Deep copy and shallow copy

Prototype pattern is all about copying objects. So it is impossible to talk about prototype without mentioning deep and shallow copy.

Shallow copy, also know as field copy, will copy all fields of the object into new object. If a field should hold reference to another object, then shallow copy will copy the reference. As such, if an object A has a reference to object B, then shallow copy A’ of object A will refer to the same object B. In C# a shallow copy can be created using the method MemberwiseClone().

Deep copy is a bit more complicated. The important distinction is that deep copy should make copies of all the objects in referenced fields as well. There are several ways to approach this problem. The safest option is to manually write the copy method, but that can be very time consuming and prone to errors as well. Alternatively deep copy can be implemented in C# by using serialization or reflection. Both of these options will however fail to copy event handlers and are likely to break down in case of circular dependencies.  

Finally there is third combination approach somewhere in the middle ground, where shared association type fields are copied as references and aggregation type relationships are copied as deep copy. This approach usually needs custom Clone implementation, however Unity 3D makes the distinction based on parent-child relationships in the scene graph. The children and components are aggregated, while parents and siblings are associated.

Prototype in Unity

Instantiate in Unity creates a combination copy of a game object, meaning it:

  • copies the game object and the complete hierarchy of all child game objects

  • copies all components of the game object and all child game objects

  • for references in components

    • All references to game objects within child hierarchy are set to new copies

    • All references to components within game object or child hierarchy are set to new copies.

    • All references to objects outside the game object or child hierarchy are copied as is.

So if you are able to encapsulate the things you want to clone as game objects, then using prototype pattern is already pretty much supported out of the box. The only last missing small step is that the objects in prototype pattern implement an interface. By implementing the prototype interface we inform the client that this object can be cloned. In component based design, we can replace the inheritance with composition and create a component for cloning.

public class Cloner : MonoBehaviour {

 

   public GameObject Clone()

{

    return Instantiate(gameObject);

}

 

}

Now the client class can use GetComponent() method to find out if a game object is cloneable. Should GetComponent return a reference to the cloner, we can go ahead and call the clone method to create a new instance of this game object.

;