Design Patterns in Swift: Prototype Pattern

These are my notes from working through the book Pro Design Patterns in Swift by Adam Freeman:

The Prototype Pattern

The prototype pattern is a design pattern in which one object is created by copying another instance of an object.

Pros of using this pattern

This pattern is beneficial in the sense that it eliminates the dependency on the initializer in order to create new objects. This can be useful when you want to avoid continuous initialization that could be expensive.

Cons of using this pattern

There are no cons in implementing the use of the this design pattern if used correctly. However, it is possible to use the wrong type of copying for the prototype object. We will talk about how to avoid this by determining the need for “shallow copying” or “deep copying”.

Setting up the pattern for use

Structures

Using the prototype pattern with a Structure is extremely easy due to Structures being value types. When a Struct instance is assigned to a variable/constant a entirely new instance is created by copying the original instances values.

Take a look at the code below:

Screen Shot 2016-04-17 at 3.13.43 PM

Here we are creating an instance of Location by calling its initializer method and passing in values for the latitude and longitude arguments. We then proceed to create another instance called newCoordinate, without the use of an initializer method, by assigning it a copy of our original instance. Now we can manipulate the properties of our new instance without affecting the original prototype.

Classes

Using the prototype pattern with Classes becomes a little more complicated due to Classes being reference types. When you assign an instance of a reference type to a variable/constant, a new instance is not created, instead a new reference pointing to the original instance in memory is created. It is essentially the same object being called by a different name.

In order to get the behavior of the object being copied on assignment, we have to implement the NSCopying protocol on our class. However, before we can do this the class needs to be subclassed from NSObject.

Take a look at the code below:
Screen Shot 2016-04-17 at 3.34.10 PM

I’ve subclassed my Person class from NSObject and implemented the NSCopying protocol. To reach protocol conformance the copyWithZone() method must be implemented in the class. Inside of this method, we will return the instance of Person that this method is called on as AnyObject.

Next, in order to create a copy of the object we have to call the copy() method on our original instance. This method is defined in NSObject and returns the object that is returned from copyWithZone(). Keep in mind that copyWithZone returns an AnyObject, so we have to type cast the returned value as the type of the original object.

We now have successfully copied our original aPerson object and assigned it to a new variable called nextPerson. We can now manipulate its properties without affecting the original object. It’s important to note that the NSCopying protocol doesn’t change reference types into value types, however, just lets you copy their values.

Shallow vs Deep Copying

Shallow copying and deep copying is a way of describing the behavior of cloning an objects properties.

Let’s take a look at another example to get some context:
Screen Shot 2016-04-17 at 3.50.53 PM.png

Here I changed our original Location structure to be a class and I added a location property to our Person class. You will now see after creating a copy of our original object, we are getting some unexpected behavior. The location properties are still pointing to the same references in memory. Why is this?

We have here what is known as a shallow copy. The references to the Location objects have been copied but not the objects themselves. In order to give the Location type the
“Deep Copying” behavior, we need to do the same thing we did with the Person class and implement the NSCopying protocol. You can only implement this protocol on Classes, therefore, a Structure will always be limited to shallow copying.

Screen Shot 2016-04-17 at 4.02.40 PM

After conforming our Location to the NSCopying protocol, we need to update the copyWithZone() method inside of the Person class. This is where we will call our copy() method for location, telling the compiler that we want a copy of the location object when Person is copied, as opposed to the copy of the reference we were receiving before.

Summary

This design pattern can be useful if you want to avoid dependencies on the initializer or in cases where the initialization is computationally expensive. When using this design pattern, you should take care to determine whether you need to be using shallow copying or deep copying to achieve your desired result. There are no firm factors for determining this, you simply need to decide which sort of behavior best suits your needs.

Leave a comment